CodeAccessSecurityAttribute derived class throwing System.TypeLoadException(加载类型时失败)

CodeAccessSecurityAttribute derived class throwing System.TypeLoadException (Failure has occurred while loading a type)

我已将自定义属性应用于 CRUD 存储库方法以控制访问:

Public Class SecureDbContextGenericRepository(Of TEntity As Class, TContext As DbContext)
  Inherits DbContextGenericRepository(Of TEntity, TContext)
  Public Sub New(connectionService As IConnectionService)
    MyBase.New(connectionService)
  End Sub
  <EmployeeRoleRequirement(SecurityAction.Demand, EmployeeRoles:=EmployeeRoles.DataWriter)>
  Public Overrides Sub Delete(ParamArray entities() As TEntity)
    MyBase.Delete(entities)
  End Sub
  <EmployeeRoleRequirement(SecurityAction.Demand, EmployeeRoles:=EmployeeRoles.DataWriter)>
  Public Overrides Sub Insert(ParamArray entities() As TEntity)
    MyBase.Insert(entities)
  End Sub
  <EmployeeRoleRequirement(SecurityAction.Demand, EmployeeRoles:=EmployeeRoles.DataReader)>
  Public Overrides Function [Select](Optional predicate As Func(Of TEntity, Boolean) = Nothing) As IList(Of TEntity)
    Return MyBase.Select(predicate)
  End Function
  <EmployeeRoleRequirement(SecurityAction.Demand, EmployeeRoles:=EmployeeRoles.DataWriter)>
  Public Overrides Sub Update(ParamArray entities() As TEntity)
    MyBase.Update(entities)
  End Sub
End Class  

这是属性的实现:

Public Class EmployeeRoleRequirementAttribute
    Inherits CodeAccessSecurityAttribute
    Public Sub New(action As SecurityAction)
      MyBase.New(action)
    End Sub

    Public Overrides Function CreatePermission() As IPermission
      Return New EmployeeRolePermission(_EmployeeRoles)
    End Function

    Public Property EmployeeRoles As EmployeeRoles
  End Class  

<Flags>
  Public Enum EmployeeRoles As Integer
    DataReader = 0
    DataWriter = 1
  End Enum

以及权限:

Public Class EmployeeRolePermission
    Implements IPermission
    Public Sub New(employeeRoles As EmployeeRoles)
      _EmployeeRoles = employeeRoles
    End Sub

    Public Function Copy() As IPermission Implements IPermission.Copy
      Return New EmployeeRolePermission(_EmployeeRoles)
    End Function
    Public Sub Demand() Implements IPermission.Demand
      Dim principal = DirectCast(Thread.CurrentPrincipal, ProductionAssistantPrincipal)
      If Not principal.IsInRole(_EmployeeRoles) Then
        Throw New SecurityException(String.Format(My.Resources.EmployeeRoleNotFound,
                                                  principal.Identity.Name,
                                                  _EmployeeRoles.ToString()))
      End If
    End Sub
    Public Sub FromXml(e As SecurityElement) Implements ISecurityEncodable.FromXml
      Throw New NotImplementedException()
    End Sub
    Public Function Intersect(target As IPermission) As IPermission Implements IPermission.Intersect
      Return New EmployeeRolePermission(_EmployeeRoles And DirectCast(target, EmployeeRolePermission).EmployeeRoles)
    End Function
    Public Function IsSubsetOf(target As IPermission) As Boolean Implements IPermission.IsSubsetOf
      Return _EmployeeRoles.HasFlag(DirectCast(target, EmployeeRolePermission).EmployeeRoles)
    End Function
    Public Function ToXml() As SecurityElement Implements ISecurityEncodable.ToXml
      Throw New NotImplementedException()
    End Function
    Public Function Union(target As IPermission) As IPermission Implements IPermission.Union
      Return New EmployeeRolePermission(_EmployeeRoles Or DirectCast(target, EmployeeRolePermission).EmployeeRoles)
    End Function

    Public ReadOnly Property EmployeeRoles As EmployeeRoles
  End Class  

每次到达其中一个 CRUD 方法时,都会抛出 TypeLoadException。我真的不知道这是什么原因,但如果我从 CRUD 方法中删除属性,一切正常。

这似乎是由于属性上的枚举值 属性(有关详细信息,请参阅 https://connect.microsoft.com/VisualStudio/feedback/details/596251/custom-cas-attributes-with-an-enum-property-set-cause-a-typeloadexception)。要解决此问题,您可以在属性上使用字符串值 属性 并在 属性 setter 中或在创建权限之前强制转换为枚举。 (就个人而言,为了启用早期验证,我可能会选择前者,但是 ymmv...)

另一种解决方法是使属性 属性 成为 Enum 中使用的类型,在本例中为 Integer。

Public Class EmployeeRoleRequirementAttribute
  Inherits CodeAccessSecurityAttribute
  Public Sub New(action As SecurityAction)
    MyBase.New(action)
  End Sub
  Public Overrides Function CreatePermission() As IPermission
    Return New EmployeeRolePermission(CType(_RequiredEmployeeRoles, EmployeeRoles))
  End Function

  Public Property RequiredEmployeeRoles As Integer
End Class

<Flags>
Public Enum EmployeeRoles As Integer
  DataReader = 0
  DataWriter = 1
End Enum

那么你就不需要使用字符串,它不允许在使用属性时轻松组合标志:

<EmployeeRoleRequirement(SecurityAction.Demand, RequiredEmployeeRoles:=EmployeeRoles.DataReader Or EmployeeRoles.DataWriter)>
Sub SecuredMethod()
End Sub