2010-07-23 79 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"); 
       } 
     } 
    } 
}