I searched a long time for a solution for my problem. I have a custom AuthorizeAttribute that needs a Dependency to a "Service" that has access to a DbContext. Sadly the Dependency Injection did not work in the custom AuthorizeAttribute and was always null.
I came up with an (for me) acceptable solution. Now I want to know if my solution can cause unforeseen behaviour?
Global.asax.cs
CustomAuthorizeAttribute.AuthorizeServiceFactory = () => unityContainer.Resolve<AuthorizeService>();
CustomAuthorizeAttribute.cs
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
public class CustomAuthorizeAttribute : AuthorizeAttribute
{
public static Func<AuthorizeService> AuthorizeServiceFactory { get; set; }
public Privilege Privilege { get; set; }
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
bool authorized = base.AuthorizeCore(httpContext);
if (!authorized)
{
return false;
}
return AuthorizeServiceFactory().AuthorizeCore(httpContext, Privilege);
}
}
AuthorizeService.cs
public class AuthorizeService
{
[Dependency]
public UserService UserService { private get; set; }
public bool AuthorizeCore(HttpContextBase httpContext, Privilege privilege)
{
ApplicationUser user = UserService.FindByName(httpContext.User.Identity.Name);
return UserService.UserHasPrivilege(user.Id, privilege.ToString());
}
}
Is this an acceptable solution? Will I run into nasty problems in the future or is there maybe a better way to use Dependency Injection in a custom AuthorizeAttribute?
ASP.NET Core supports the dependency injection (DI) software design pattern, which is a technique for achieving Inversion of Control (IoC) between classes and their dependencies.
A View Component class can be created in the following ways. Same as Controller class, View Component class must be non-abstract, public, and non-nested. This class fully supports constructor dependency injection.
Dependency Injection is the design pattern that helps us to create an application which loosely coupled. This means that objects should only have those dependencies that are required to complete tasks.
The Dependency Injection pattern is a particular implementation of Inversion of Control. Inversion of Control (IoC) means that objects do not create other objects on which they rely to do their work. Instead, they get the objects that they need from an outside source (for example, an xml configuration file).
I have a custom AuthorizeAttribute that needs a Dependency to a "Service" that has access to a DbContext. Sadly the Dependency Injection did not work in the custom AuthorizeAttribute and was always null.
An implementation of IControllerFactory
in the System.Web.Mvc
namespace creates instances your Controllers for web requests. The Controller Factory uses System.Web.Mvc.DependencyResolver
to resolve dependencies in each controller.
However, ActionFilters/Attributes in the MVC pipeline are not created from the Controller Factory so dependencies are not resolved using System.Web.Mvc.DependencyResolver
. This is why your dependency was always null
.
Now, System.Web.Mvc.DependencyResolver
is public
and static
so you can access it yourself.
public class AuthorizeService : AuthorizeAttribute
{
private UserService UserService
{
get
{
return DependencyResolver.Current.GetService<UserService>();
}
}
public bool AuthorizeCore(HttpContextBase httpContext, Privilege privilege)
{
ApplicationUser user = UserService.FindByName(httpContext.User.Identity.Name);
return UserService.UserHasPrivilege(user.Id, privilege.ToString());
}
}
Assuming your UserService
has a dependency scope of WebRequest, i.e. its lifetime is One Per web request and tied to the lifetime of HttpContext
of a web request this will not construct a new UserService
if one has been resolved previously or after if this is the first time UserService
has been resolved for the given web request.
In ASP.NET Core you can request services easily as below:
public class CustomAuthAttribute : AuthorizeAttribute, IAuthorizationFilter
{
public async void OnAuthorization(AuthorizationFilterContext context)
{
// var user = context.HttpContext.User;
// if (!user.Identity.IsAuthenticated)
// {
// context.Result = new UnauthorizedResult();
// return;
// }
var userService = context.HttpContext.RequestServices.GetService(typeof(UserService)) as UserService;
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With