2010-07-23 31 views
3

我有一个使用自定义UsernamePasswordValidator的WCF服务。验证器需要访问我的实体框架上下文。访问WCF中的当前InstanceContext UsernamePasswordValidator

我想为整个服务调用创建一个ObjectContext,然后在调用结束时销毁/处理它。因此,我创建了一个提供此功能的单例静态类,但是,现在发生的情况是,如果两个服务调用并发发生,其中一个调用会处理单例。

我要么保留对ObjectContext的本地引用,在这种情况下,使用它的第二个服务将它视为已丢弃并引发错误,或者,我在任何需要它的地方将Singleton类放在一个包装器属性中,然后全部我的更改会被抛弃,因为如果另一个调用已经处理了该对象,那么我将获得该对象的一个​​新实例。

所以基本上我的问题是如何实例化一个ObjectContext每个服务调用?

注意:实例需要在服务代码和自定义UsernamePasswordValidator代码中都可以访问。

我不能只是在构造函数中使用它或使用using语句,因为然后自定义UsernamePasswordValidator无法访问它。有没有办法让每个通话都有一个静态类?这听起来不可能,但是这是怎么回事?我应该在会话中缓存对象吗?

我的服务托管在IIS中。

UPDATE:
所以我钉下来到使用IExtension对象中的InstanceContext存储状态。但是,如何访问UsernamePasswordValidator中的当前InstanceContext?

回答

2

好的,所以最后我通过使用下面的静态类并依靠ASP.NET来缓存我的上下文来解决它。

我不确定这是否是最好的办法,但是这允许我为每个请求使用一个ObjectContext,所以我不会旋转太多,这也意味着我不必使用锁定对象,如果许多用户使用该服务,这将成为噩梦。

public static class MyContextProvider 
    { 
     public static MyModel Context 
     { 
      get 
      { 
       if (HttpContext.Current.Items["context"].IsNull()) 
       { 
        HttpContext.Current.Items["context"] = new MyModel(); 
       } 

       return HttpContext.Current.Items["context"] as MyModel; 
      } 
     }  
    } 

那么无论我在应用程序需要一个ObjectContext的我只是叫

var context = MyContextProvider.Context; 
0

为您服务,您可以指定一个服务行为里面详细介绍了服务的实例模式:

[ServiceBehaviour(InstanceContextMode = InstanceContextMode.PerCall)] 
public class MyService : IMyService { 
    ObjectContext context; 
} 
+0

我已经拥有该属性。我遇到的问题是在实际服务代码和UsernamePasswordValidator代码之间共享上下文。 – 2010-07-23 09:55:47

1

你必须每次调用一个实例,你也有每个实例1级的呼叫。

所以它应该非常简单,在OperationContract方法的顶层使用using() { }块。

+0

大声笑,我不敢相信我没有想到这么明显的东西:( – 2010-07-23 09:49:19

+0

这不会工作。这对OperationContract方法很好,但自定义UsernamePasswordValidator被调用之前,我到达OperationContract方法。特别是想要在每次调用时抛出两个ObjectContexts ...如果还有其他方法,我会跳过它。 – 2010-07-23 09:52:04

0

一个清洁的方式,可能是使用ServiceAuthenticationManager,这是在.NET 4。

http://msdn.microsoft.com/en-us/library/system.servicemodel.serviceauthenticationmanager.aspx

Authenticate方法(您将覆盖)可以在其上访问消息对象和设置属性。我没有用它在愤怒,所以YMMV :)

编辑这种方法的问题是,你没有用户名和密码,所以仍然需要自定义身份验证。

看一看的UsernameSecurityTokenAuthenticator ... http://msdn.microsoft.com/en-us/library/system.identitymodel.selectors.usernamesecuritytokenauthenticator(v=vs.90).aspx


从我的研究进一步阅读:

这个问题的答案提供了有关如何使用它的一些提示:

Custom WCF authentication with System.ServiceModel.ServiceAuthenticationManager?

如果你可以阅读(或忽略)俄语,我发现有用的

http://www.sql.ru/forum/actualthread.aspx?tid=799046

这个相当好CodeProject上的文章更进一步(加密和压缩以及自定义授权)

http://www.codeproject.com/Articles/165844/WCF-Client-Server-Application-with-Custom-Authenti

1

好吧,这里是线程安全的静态类:为L提示方法,它为任何WCF服务调用提供单个ObjectContext实体模型对象,并在调用结束时自动处理它:

public static class EntityModelProvider 
{ 
    private static readonly Dictionary<OperationContext, MyEntityModel> _entityModels = new Dictionary<OperationContext, MyEntityModel>(); 

    public static MyEntityModel GetEntityModel() 
    { 
     if (OperationContext.Current == null) 
      throw new Exception("OperationContext is missing"); 

     lock (_entityModels) 
     { 
      if (!_entityModels.ContainsKey(OperationContext.Current)) 
      { 
       _entityModels[OperationContext.Current] = new MyEntityModel(); 
       OperationContext.Current.OperationCompleted += delegate 
       { 
        lock (_entityModels) 
        { 
         _entityModels[OperationContext.Current].Dispose(); 
         _entityModels.Remove(OperationContext.Current); 
        } 
       }; 
      } 

      return _entityModels[OperationContext.Current]; 
     } 
    } 
0

当您分配给服务时,为什么不将上下文传递到您的CustomValidator中 - 将您的对象上下文存储在验证程序中,并且在重写的验证方法中如果需要将其更新。然后您仍然可以通过Services CutomUserNameValidator访问该对象。

取决于您所问的内容: 将您的单独ObjectContext类创建为动态对象 - 将该属性添加为您的属性CustomValidator。 在您的自定义验证器中 - 您现在可以检查该对象是否已处理,并在需要时再次创建该对象。 否则,如果这不是你所追求的 - 只需将上下文存储在验证器中 - 您仍然可以在服务器端进行访问。 这里的代码只是一个普遍的想法 - 我只是把它作为一个参考框架发布,所以你可以有一个想法,我在说什么。

public DynamicObjectContextObjectClass 
{ 
    ObjectContext internalObjectContext; 

} 
public class ServiceUserNamePasswordValidator : UserNamePasswordValidator 
{ 

    public DynamicObjectContextObjectClass dynamiccontext; 


    public override void Validate(string userName, string password) 
    { 
     if(dynamiccontext.internalObjectContext.isdisposed) 
     { 

     dynamiccontext.internalObjectContext = new Context; 

      } 
      try 
      { 
       if (string.IsNullOrEmpty(userName) || password == null) 
       { 
        //throw new ArgumentNullException(); 
        throw new FaultException("Username cannot be null or empty; Password cannot be null and should not be empty"); 
       } 
     } 
    } 
}