public void AssertCurrentUserHasCapability(CapabilitiesAssertionSpec assertionSpec) { if (assertionSpec == null) { throw new ArgumentNullException(nameof(assertionSpec)); } var capabilityType = GetCapabilityType(assertionSpec.CapabilityAttribute); var requiredCapability = assertionSpec.CapabilityAttribute.RequiredCapability; var entityType = entityTypeProvider.GetEntityType(requiredCapability); if (entityType == null) { throw new CapabilitiesCouldNotBeCheckedException($@"No entity type could be found to match the capability type {capabilityType}. Every type of required capability must have a corresponding entity type, provided by the service {nameof(IGetsEntityTypeForCapability)}. Have you forgotten to add the entity type to the default implementation of that service?"); } if (logger.IsDebugEnabled) { logger.Debug($@"Executing {OpenGenericAssertMethod.Name} to assert that the user has required capabilities. Action name: {assertionSpec.ActionName} Entity type: {entityType.FullName} Capability type: {capabilityType.FullName}"); } // Need to use reflection to get into the generic method from a non-generic one. // The trade-off is worth it IMO, because it allows the rest of the capabilities stack 'from here downwards' to be strongly-typed. var method = OpenGenericAssertMethod.MakeGenericMethod(entityType, capabilityType); method.Invoke(this, new[] { assertionSpec.ParameterValue, requiredCapability, assertionSpec.ActionName }); }
Type GetEntityType(ParameterInfo param) { var capabilityAttribute = param.GetCustomAttribute <RequireCapabilityAttribute>(); if (capabilityAttribute == null) { return(null); } return(entityTypeProvider.GetEntityType(capabilityAttribute.RequiredCapability)); }