Search code examples
vb.netpermissionscode-access-security

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


I have custom attribute applied to CRUD repository methods to control access:

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  

This is implementation of attribute:

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

And permission:

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  

Every time one of the CRUD methods are reached, TypeLoadException is thrown. I really dont know cause of this, but if I remove attributes from CRUD methods, everything works fine.


Solution

  • This seems to be due to the enum-valued property on the attribute (see https://connect.microsoft.com/VisualStudio/feedback/details/596251/custom-cas-attributes-with-an-enum-property-set-cause-a-typeloadexception for details). To work around this issue, you could use a string-valued property on the attribute and cast to an enum either in the property setter or just before creating the permission. (Personally, I'd probably opt for the former in the interests of enabling early validation, but ymmv...)