2009-07-27 27 views
1

我有一個HttpModule在每個請求上創建一個CommunityPrincipal(實現IPrincipal接口)對象。我想以某種方式爲每個請求存儲對象,所以我可以在需要時隨時獲取它,而無需執行演員製作或再次創建。在請求期間訪問/使用相同的對象 - asp.net

基本上我想模仿FormsAuthenticationModule的工作方式。 它爲每個請求分配HttpContext.User屬性一個實現IPrincipal接口的對象。

我不知何故希望能夠調用等HttpContext.MySpecialUser(或MySpecialContext.MySpecialUser - 可以創建靜態類),這將返回我的對象​​(特定類型)。

我可以使用擴展方法,但我不知道如何存儲對象,因此可以在請求期間訪問它。

這是如何實現的?

請注意,我想將其作爲特定類型(CommunityPrincipal - 不只是作爲對象)存儲。 它當然只適用於正在處理的當前請求,不能與所有其他線程/請求共享。

現在我將我的CommunityPrincipal對象分配給HttpModule中的HttpContext.User,但它需要我每次執行強制轉換,我需要使用未在IPrincipal接口中定義的CommunityPrincipal對象上的屬性。

回答

0

將自定義主體分配給Context.User是正確的。希望你在Application_AuthenticateRequest中做到這一點。

回答你的問題,你是否只從ASPX頁面訪問用戶對象?如果是這樣,你可以實現一個自定義的基礎頁面,其中包含你的演員陣容

public class CommunityBasePage : Page 
{ 
    new CommunityPrincipal User 
    { 
     get { return base.User as CommunityPrincipal; } 
    } 
} 

然後,讓你的網頁從CommunityBasePage繼承,你就能夠從this.User得到所有的屬性。

+0

感謝您的回覆。 這也是一個好主意。我通常會在控制器或視圖中使用它所以我可以創建一個自定義視圖和自定義控制器,我可以繼承。謝謝。 – MartinF 2009-10-13 15:19:10

0

既然你已經存儲HttpContext.User屬性的對象的所有你真的需要acheive你的目標是acheives你的目標一個靜態方法: -

public static class MySpecialContext 
    { 
    public static CommunityPrinciple Community 
    { 
     get 
     { 
      return (CommunityPrinciple)HttpContext.Current.User; 
     } 
    } 
    } 

現在你可以得到CommunityPrinciple如下: -

var x = MySpecialContext.Community; 

但是它似乎是一個很大的努力,要避免過分: -

var x = (CommunityPrinciple)Context.User; 

另一種方法是對HttpContext的擴展方法: -

public static class HttpContextExtensions 
    { 
    public static CommunityPrinciple GetCommunity(this HttpContext o) 
    { 
     return (CommunityPrinciple)o.User; 
    } 
    } 

使用它: -

var x = Context.GetCommunity(); 

這是相當整潔,但需要你記住要包括命名空間的擴展類的定義,其中在每個文件的使用列表中都需要它。

編輯

讓我們假設對你有一些非常好的理由,甚至擔綱演出中稱爲上面的代碼的那一刻仍然是不可接受的(順便說一句,我會非常有興趣瞭解什麼情況引導你得出這個結論)。

又一替代方案是ThreadStatic字段: -

public class MyModule : IHttpModule 
    { 
    [ThreadStatic] 
    private static CommunityPrinciple _threadCommunity; 

    public static CommunityPrinciple Community 
    { 
     get 
     { 
      return _threadCommunity; 
     } 
    } 
    // Place here your original module code but instead of (or as well as) assigning 
    // the Context.User store in _threadCommunity. 
    // Also at the appropriate point in the request lifecyle null the _threadCommunity 

    } 

甲場與[ThreadStatic]裝飾將具有每個線程的存儲的一個實例。因此,多個線程可以修改和讀取_threadCommunity,但每個線程都將在其特定的實例上運行。

+0

感謝您的回覆。這就是我已經在做:)。我所要求的是,如果有一種方法可以避免每次需要使用CommunityPrincipal對象時顯式強制轉換。如果有某種技術可以將其作爲CommunityPrincipal存儲並使其可用於每個請求。等我想創建一個靜態類,這是「創建」每個線程(ThreadStaticAttribute),但我不知道它是否會是一個安全問題,因爲我將不得不確保該對象在每個請求的末尾被刪除作爲線程被共享/重用。 – MartinF 2009-08-02 12:35:20

1

我建議您遠離將數據耦合到線程本身。您無法控制現在或將來asp.net如何使用線程。

數據與請求上下文非常緊密,所以應該根據上下文定義,生存並且死掉。這是恰當的放置它的地方,並且在HttpModule中實例化對象也是合適的。

演員真的不應該是一個問題,但如果你想擺脫這一點,我會強烈建議爲此HttpContext擴展方法...這正是那種情況下,擴展方法被設計來處理。

這是我如何會實現它:

創建一個靜態類把擴展方法:

public static class ContextExtensions 
{ 
    public static CommunityPrinciple GetCommunityPrinciple(this HttpContext context) 
    { 
     if(HttpContext.Current.Items["CommunityPrinciple"] != null) 
     { 
      return HttpContext.Current.Items["CommunityPrinciple"] as CommunityPrinciple; 
     } 
    } 
} 

在你的HttpModule只是把主到右鍵項集合,如:

HttpContext.Current.Items.Add("CommunityPrincipal", MyCommunityPrincipal); 

這將常規上下文的用戶屬性保持在自然狀態,以便第三方代碼,框架代碼和其他任何您編寫的東西不會因爲擁有tam與正常的IPrincipal一起在那裏發展。該實例僅在用戶請求有效時才存在。最重要的是,該方法可用於編寫代碼,就好像它只是任何常規的HttpContext成員....並且不需要強制轉換。

+0

感謝您的回覆。 我將對象作爲IPrincipal存儲在context.user上,然後使用擴展方法對任何類型執行顯式強制轉換。這似乎是我能得到的最好的。 我希望有可能做某種特定類型的屬性,我可以像context.user一樣使用,而不是通過HttpContext.Items將擴展方法或存儲爲HttpContext上的對象。顯然不是。 – MartinF 2009-10-13 15:17:46

相關問題