如何使用具有属性的依赖注入? [英] How to use dependency injection with an attribute?

查看:22
本文介绍了如何使用具有属性的依赖注入?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我正在创建的 MVC 项目中,我有以下 RequirePermissionAttribute 可用于需要特定权限的任何操作(此示例已简化):

In an MVC project I'm creating I have the following RequirePermissionAttribute that gets put on any action that needs specific permissions (it's been simplified for this example):

public class RequirePermissionAttribute : ActionFilterAttribute, IAuthorizationFilter
{
    public Operation Permissions { get; set; }

    public RequirePermissionAttribute() { }

    public RequirePermissionAttribute(Operation permissions)
    {
        this.Permissions = permissions;
    }

    public bool AuthorizeCore(HttpContextBase httpContext)
    {
        IAuthorizationService authServ = new ASPNETAuthorizationService();
        return authServ.Authorize(httpContext);
    }

    public void OnAuthorization(AuthorizationContext filterContext)
    {
        Enforce.ArgNotNull(filterContext);

        if (this.AuthorizeCore(filterContext.HttpContext))
        {
            // code snipped.
        }
        else
        {
            // code snipped.
        }
    }
}

所以这个问题显然是我的授权属性依赖于我创建的 ASPNETAuthorizationService.由于属性是编译时检查的,所以我不能采用构造函数的方式.

So the problem obviously with this is that my authorize attribute has a dependency on the ASPNETAuthorizationService that I created. I can't go the constructor way since attributes are compile-time checked.

有一件事要提到,我正在使用我自己制作的小 IoC,它不支持属性注入(目前).当然,如果我真的走属性注入路线,我必须添加对它的支持(我必须做一些研究).

One thing to mention, I'm using my own little IoC that I made and it doesn't have support for property injection (yet). Of course, if I did go the property injection route, I'd have to add support for it (which I'd have to do some research on).

向属性类注入内容的最佳方法是什么?

What's the best way to inject something into an attribute class?

推荐答案

向属性类注入内容的最佳方法是什么?

What's the best way to inject something into an attribute class?

严格来说,我们不能使用依赖注入将依赖注入到属性中.属性用于元数据而不是行为.[AttributeSpecification()] 通过禁止引用类型作为参数来鼓励这一点.

Strictly speaking, we cannot use dependency injection to inject a dependency into an attribute. Attributes are for metadata not behavior. [AttributeSpecification()] encourages this by forbidding reference types as arguments.

您可能正在寻找的是同时使用属性和过滤器,然后将依赖项注入过滤器.属性添加元数据,决定是否应用过滤器,过滤器接收注入的依赖.

What you're probably looking for is to use an attribute and a filter together, and then to inject dependencies into the filter. The attribute adds metadata, which determines whether to apply the filter, and the filter receives the injected dependencies.

如何使用带有属性的依赖注入?

How to use dependency injection with an attribute?

这样做的理由很少.

也就是说,如果您打算注入属性,则可以使用 ASP.NET Core MVC IApplicationModelProvider.框架将依赖传递给提供者的构造函数,提供者可以将依赖传递给属性的属性或方法.

That said, if you're intent on injecting into an attribute, you can use the ASP.NET Core MVC IApplicationModelProvider. The framework passes dependencies into the provider's constructor, and the provider can pass dependencies to the attribute's properties or methods.

在您的 Startup 中,注册您的提供商.

In your Startup, register your provider.

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Mvc.ApplicationModels;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.TryAddEnumerable(ServiceDescriptor.Transient
            <IApplicationModelProvider, MyApplicationModelProvider>());

        services.AddMvc();
    }

    public void Configure(IApplicationBuilder app)
    {
        app.UseMvc();
    }
}

在提供者中使用构造函数注入,并将这些依赖项传递给属性.

Use constructor injection in the provider, and pass those dependencies to the attribute.

using System.Linq;
using Microsoft.AspNetCore.Mvc.ApplicationModels;
using Microsoft.AspNetCore.Mvc.Routing;

public class MyApplicationModelProvider : IApplicationModelProvider
{
    private IUrlHelperFactory _urlHelperFactory;

    // constructor injection
    public MyApplicationModelProvider(IUrlHelperFactory urlHelperFactory)
    {
        _urlHelperFactory = urlHelperFactory;
    }

    public int Order { get { return -1000 + 10; } }

    public void OnProvidersExecuted(ApplicationModelProviderContext context)
    {
        foreach (var controllerModel in context.Result.Controllers)
        {
            // pass the depencency to controller attibutes
            controllerModel.Attributes
                .OfType<MyAttribute>().ToList()
                .ForEach(a => a.UrlHelperFactory = _urlHelperFactory);

            // pass the dependency to action attributes
            controllerModel.Actions.SelectMany(a => a.Attributes)
                .OfType<MyAttribute>().ToList()
                .ForEach(a => a.UrlHelperFactory = _urlHelperFactory);
        }
    }

    public void OnProvidersExecuting(ApplicationModelProviderContext context)
    {
        // intentionally empty
    }
}

使用可以接收依赖项的公共 setter 创建一个属性.

Create an attribute with public setters that can receive dependencies.

using System;
using Microsoft.AspNetCore.Mvc.Routing;

public sealed class MyAttribute : Attribute
{
    private string _someParameter;

    public IUrlHelperFactory UrlHelperFactory { get; set; }

    public MyAttribute(string someParameter)
    {
        _someParameter = someParameter;
    }
}

将该属性应用于控制器或操作.

Apply the attribute to a controller or an action.

using Microsoft.AspNetCore.Mvc;

[Route("api/[controller]")]
[MyAttribute("SomeArgument")]
public class ValuesController : Controller
{
    [HttpGet]
    [MyAttribute("AnotherArgument")]
    public string Get()
    {
        return "Foobar";
    }
}

上面演示了一种方法,对于罕见的用例,您可以将依赖项注入到属性中.如果您找到这样做的正当理由,请将其发布在评论中.

The above demonstrates one way, for the rare use case, that you can inject dependencies into an attribute. If you figure out a valid reason to do this, please post it in the comments.

这篇关于如何使用具有属性的依赖注入?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆