Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
80 views
in Technique[技术] by (71.8m points)

c# - Dependency Injection in attributes

I am trying to inject a dependency into a custom AuthorizeAttribute as follows:

public class UserCanAccessArea : AuthorizeAttribute
{
    readonly IPermissionService permissionService;

    public UserCanAccessArea() :
        this(DependencyResolver.Current.GetService<IPermissionService>()) { }

    public UserCanAccessArea(IPermissionService permissionService)
    {
        this.permissionService = permissionService;
    }

    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        string AreaID =
            httpContext.Request.RequestContext.RouteData.Values["AreaID"] as string;

        bool isAuthorized = false;

        if (base.AuthorizeCore(httpContext))
            isAuthorized = permissionService.UserCanAccessArea(AreaID, httpContext.User);

        return isAuthorized;
    }
}

This works but seems to be resolving as a singleton meaning I get the problems described in my pervious question

What I'd like to do is use property injection but as my Attribute itself is not resolved by Unity I'm unable to find a way to configure the container to intercept and resolve a property. I have tried the following:

public class UserCanAccessArea : AuthorizeAttribute
{
    public IPermissionService permissionService { get; set; }

    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        string AreaID =
            httpContext.Request.RequestContext.RouteData.Values["AreaID"] as string;

        bool isAuthorized = false;

        if (base.AuthorizeCore(httpContext))
            isAuthorized = permissionService.UserCanAccessArea(AreaID, httpContext.User);

        return isAuthorized;
    }
}

Container:

container.RegisterType<UserCanAccessArea>(new InjectionProperty("permissionService"));

But the property is always null at runtime.

Has anyone achieved this and if so do you have an example?

Question&Answers:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You should prevent doing dependency injection into attributes completely. The reason for this is explained in this article: Dependency Injection in Attributes: don’t do it!. In summary the article explains that:

  • Constructor injection is not possible, because creation of an Attribute instance cannot be intercepted; the CLR is in control.
  • The use of property injection is fragile, since it results in Temporal Coupling, which should be prevented.
  • Dependency injection into attributes makes it impossible to verify the correctness of the container's configuration.
  • Frameworks like MVC and Web API cache attributes, making it very easy to accidentally create captive dependencies causing bugs.

You have two choices here:

  1. Make the attributes passive, by splitting the data (the attribute) from its behavior (the service) as explained in the referenced article and this related article from Mark Seemann.
  2. Turn your attributes into humble objects as explained in this answer. This means you:
    1. extract all logic from the attribute into a custom service that contains all dependencies.
    2. Register that service in your container.
    3. let the attribute's method (AuthorizeCore in your case) do nothing more than resolving the service from the service locator / DependencyResolver and call the service's method. Important to note here is that you cannot do constructor injection, property injection and the service cannot be stored in the attributes private state (as you already noticed).

Which option to use:

  • Use option 1 if you are very keen into keeping your design clean, or you have more than a few attributes that you need to apply this way, or you want to apply attributes are defined in an assembly that doesn't depend on System.Web.Mvc.
  • Use option 2 otherwise.

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...