MVC.NET-缓存用户对象,以提供应用程序的数据(询问总结)



我真的很感谢一些建议,以帮助我使用对象缓存。这是我的需求:我想将控制器的某些操作相应地将其角色保存在SQL数据库中。

我现在正在做的是:当完成当前用户的第一个请求时,我会生成一个用SQL查询的某些属性的对象。我正在使用自定义提供商将此对象存储到会话中,并且我正在使用自定义角色提供商来处理授权过滤器标签。如果会话过期用户被再生..这是类似的(简化):

用户类

Public class User
   public property Login as string
   public property IsAdmin as boolean
   public sub Init(byval pLogin as string)
        Login = pLogin
        //Do some logic on database to provides roles....
        IsAdmin = dbReturnIsAdmin
   end sub
   public readonly property RolesList as string()
       Get
          Return New String() {If(IsAdmin, "UserIsAdmin", "")}
       End get
   end property 
End class

会话用户提供商

Public Class SessionProvider
   Private Const SESSION_USER As String = "SESSION_USER"
    Public Shared Sub ReloadUser()
        //'This instruction initiate user and load roles into an User class type object
        HttpContext.Current.Session(SESSION_USER) = StructureService.GetInitializedUser(My.User.Name, UowProvider.StructureUow)
    End Sub
    Public Shared ReadOnly Property User() As Application.User
        Get
            //'If user doesn't exist so we create an user
            If HttpContext.Current.Session(SESSION_USER) Is Nothing Then ReloadUser()
            //'Return user
            Return CType(HttpContext.Current.Session(SESSION_USER), Application.User)
        End Get
    End Property
End Class

自定义角色提供商

Public Class AuthentifiedRoleProvider
    Inherits RoleProvider
    //Implement base role provider....
    Public Overrides Function GetRolesForUser(username As String) As String()
        return SessionProvider.User.RolesList
    End Function
End Class

实现 - webconfig

    <system.web> .....
     <roleManager cacheRolesInCookie="false" defaultProvider="DefaultRoleProvider" enabled="true">
         <providers>
             <clear />
             <add name="DefaultRoleProvider" type="AuthentifiedRoleProvider" />
         </providers>
     </roleManager>     
   </system.web>

实现 - 控制器

    <Authorize(Roles:="UserIsAdmin")>
    Public Function List_Items() As ActionResult
        Return View()
    End Function

它正在工作...

但是,我想知道这是否真的是实现这一目标的好方法。由于我在应用程序上有一个站点地图,该站点是指控制器操作,因此SessionProvider用户(顺便说一句HTTP会话)每个菜单加载4或5倍。

所以,我的问题是:

  • 存储在会议中会带来绩效问题吗?
  • 是否有更好的方法将我的用户对象存储到一种缓存中( ->我考虑system.runtime.cache)。
  • 无论如何,您认为这种实现是有益的吗?

非常感谢!

无论如何,您认为此实现是有益的吗?

可能不是。

  1. 由于某种原因,您将会话状态与用户配置文件数据联系在一起。Session State与授权/身份验证无关,不建议将其用于用户配置文件数据,因为使用会话状态(从任何实际意义上讲)意味着您每HTTP请求需要2个其他网络请求到您的应用程序。此外,这些额外的请求是否已登录,都会发生。
  2. MvcSiteMapProvider不依赖会话状态。它使用共享缓存将节点存储在RAM中,并使用AuthorizeAttribute确定要显示/hide的节点。

如果您发现自己每次请求多次请求相同的数据,则应尝试通过使用类似的标准缓存检索模式来利用请求缓存HttpContextBase.Items):

Public Function GetSomeData() As ISomeData
    Dim key As String = "SomeDataKey"
    ' Me.cache refers to HttpContextBase.Items injected through 
    ' the constructor of this class and stored in a private field
    Dim someData As ISomeData = TryCast(Me.cache(key), ISomeData) 
    If someData Is Nothing Then
        ' The data is not cached, so look it up and populate the cache
        someData = GetDataFromExternalSource()
        Me.cache(key) = someData
    End If
    Return someData
End Function

将类似的方法放入组件之间共享的服务中,这意味着您不必担心请求中多次检索相同的数据 - 首次将其击中外部源,每次额外的时间将使用缓存。

另外,每个msdn:

创建自定义角色提供商的主要原因有两个。

  1. 您需要将角色信息存储在.NET框架中包含的角色提供商不支持的数据源中,例如FOXPRO数据库,Oracle数据库或其他数据源。
  2. 您需要使用与使用.NET框架的提供商使用的数据库模式不同的数据库架构来管理角色信息。一个常见的例子是公司或网站SQL Server数据库中已经存在的角色数据。

因此,如果您不做这些事情中的任何一个,那也可能不是正确的选择。大多数现代应用程序都可以使用/扩展ASP.NET身份进行用户身份验证,所有MVC应用程序都应使用授权tribute(或IT的子类)进行授权。

System.Runtime.Cache.ObjectCache(和MemoryCache)是用户之间通常不共享的缓存数据的好方法。如果您设计了缓存键,则可以将其用于用户数据,以便为用户包含唯一的标识符以及使密钥唯一的定界符...

Dim key As String = UserId & "|UserProfile"

也就是说,您应该意识到以这种方式缓存不会扩展到多个服务器。

无论如何,我建议您三思而后行地遵循建议。在许多情况下,MVC使我们免于不得不使用会话状态 - 除非绝对需要,否则我们不应该使用它。

多亏了建议,我将会话用户提供商更改为使用缓存。它必须扩展,但现在我可以看到更改!

会话用户提供商

   Public Class UserProvider

    Private Const USER_CACHE_PREFIX As String = "User|"
    Private Shared Sub AddUserToCache(ByVal pLogin As String, ByVal pUser As Application.User)
        Dim objCache As ObjectCache = MemoryCache.Default
        objCache.Add(USER_CACHE_PREFIX & pLogin, pUser, New CacheItemPolicy With {.SlidingExpiration = TimeSpan.FromSeconds(20)})
    End Sub
    Private Shared Function GetUserFromCache(ByVal pLogin As String) As Application.User
        Dim objCache As ObjectCache = MemoryCache.Default
        //Return cache if exists
        If objCache.Contains(USER_CACHE_PREFIX & pLogin) Then
            Return CType(objCache.GetCacheItem(USER_CACHE_PREFIX & pLogin).Value, Application.User)
        Else
            Return Nothing
        End If
    End Function
    Public Shared Function ReloadUser(ByVal pLogin As String) As Application.User
        Dim objCache As ObjectCache = MemoryCache.Default
        Dim tmpLogin As String = My.User.Name
        //Clear cache
        If objCache.Contains(USER_CACHE_PREFIX & tmpLogin) Then objCache.Remove(USER_CACHE_PREFIX & pLogin)
        Dim tmpUser As Application.User = StructureService.GetInitializedUser(pLogin, UowProvider.StructureUow) 
        AddUserToCache(tmpLogin, tmpUser)
        return tmpUser
    End Function
    Public Shared ReadOnly Property User() As Application.User
        Get
            Dim tmpLogin As String = My.User.Name
            //Try to get user from cache
            Dim tmpUser As Application.User = GetUserFromCache(tmpLogin)
            //If user is null then init and cache
            If tmpUser Is Nothing Then
                tmpUser = StructureService.GetInitializedUser(tmpLogin, UowProvider.StructureUow) 
                AddUserToCache(tmpLogin, tmpUser)
            End If
            //return  user
            Return tmpUser
        End Get
    End Property
End Class

最新更新