访问WCF UsernamePasswordValidator中的当前InstanceContext

我有一个使用自定义UsernamePasswordValidator的WCF服务。 validation器需要访问我的entity framework上下文。

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

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

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

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

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

我的服务托管在IIS中。

更新:
所以我已经把它钉在了使用IExtension对象在InstanceContext中存储状态。 但是如何在UsernamePasswordValidator中访问当前的InstanceContext?

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

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

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

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

 public static class EntityModelProvider { private static readonly Dictionary _entityModels = new Dictionary(); 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]; } } 

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

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

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

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

Authenticate方法(您将覆盖它),您可以访问Message对象并在其上设置属性。 我没有在愤怒中使用它,所以YMMV 🙂

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

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


进一步阅读我的研究:

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

使用System.ServiceModel.ServiceAuthenticationManager进行自定义WCF身份validation?

如果你能阅读(或忽略)俄语,我发现有用的提示:

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

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

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

为什么不在分配给服务时将上下文传递到CustomValidator中 – 将对象上下文存储在validation器中,如果需要,则在重写的validation方法中新建它。 然后,您仍然可以通过Services CutomUserNameValidator访问该对象。

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

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