【问题标题】:Access the current InstanceContext in a WCF UsernamePasswordValidator访问 WCF UsernamePasswordValidator 中的当前 InstanceContext
【发布时间】:2010-07-23 09:38:08
【问题描述】:

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

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

我要么保留对 ObjectContext 的本地引用,在这种情况下,使用它的第二个服务将其视为已释放并抛出错误,或者,我在 Singleton 类周围放置一个包装器属性,无论我需要它,然后我的所有更改会被丢弃,因为如果另一个调用已处理它,我将获得该对象的新实例。

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

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

我不能只在构造函数中执行此操作或使用 using 语句,因为这样 自定义 UsernamePasswordValidator 无法访问它。有没有办法让每次调用都有一个静态类?听起来确实不可能,但是解决方法是什么?我应该在会话中缓存对象吗?

我的服务托管在 IIS 中。

更新:
因此,我已将其确定为使用 IExtension 对象在 InstanceContext 中存储状态。但是如何在 UsernamePasswordValidator 中访问当前的 InstanceContext?

【问题讨论】:

    标签: c# wcf wcfserviceclient


    【解决方案1】:

    好的,所以最后我通过使用以下静态类并依靠 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;
    

    【讨论】:

      【解决方案2】:

      每次调用都有一个实例,每个实例也有 1 个调用。

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

      【讨论】:

      • 大声笑,我不敢相信我没有想到这么明显的事情:(
      • 这行不通。 OperationContract 方法很好,但是在我到达 OperationContract 方法之前调用了自定义 UsernamePasswordValidator。我不想每次调用都旋转两个 ObjectContexts...如果有任何其他方式我会跳上它。
      【解决方案3】:

      好的,这是具有线程安全静态方法的类,它为任何 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];
              }
          }
      

      【讨论】:

        【解决方案4】:

        对于您的服务,您可以指定详细说明服务实例模式的服务行为:

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

        【讨论】:

        • 我已经有那个属性了。我遇到的问题是在实际服务代码和 UsernamePasswordValidator 代码之间共享上下文。
        【解决方案5】:

        更简洁的方法可能是使用 .NET 4 中的 ServiceAuthenticationManager。

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

        通过Authenticate 方法(您将覆盖该方法),您可以访问 Message 对象并在其上设置属性。我没有在愤怒中使用它,所以 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

        【讨论】:

          【解决方案6】:

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

          取决于您的要求: 将您单独的 ObjectContext 类创建为动态对象 - 将其作为属性添加到您的 CustomValidator。 在您的自定义验证器中 - 您现在可以检查对象是否已处置并在需要时再次创建对象。 否则,如果这不是您所追求的 - 只需将 Context 存储在验证器中 - 您仍然可以在服务器端访问。 这里的代码只是一个概括的想法——我只是将它作为一个参考框架发布,这样你就可以知道我在说什么。

          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");
                          }
                 }
             }
          } 
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2011-08-02
            • 2014-05-30
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多