c# - 如何使用属性的依赖注入(inject)?

标签 c# .net asp.net-mvc dependency-injection

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

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。我不能采用构造函数方式,因为属性是编译时检查的。

有一件事要提一下,我正在使用我自己制作的小 IoC,它不支持属性注入(inject)(目前)。当然,如果我确实采用了属性注入(inject)路线,我必须为其添加支持(我必须对此进行一些研究)。

将某些东西注入(inject)属性类的最佳方法是什么?

最佳答案

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

严格来说,我们不能使用依赖注入(inject)来将依赖注入(inject)到属性中。 Attributes are for metadata不是行为。 [AttributeSpecification()] 通过禁止引用类型作为参数来鼓励这一点。

您可能正在寻找的是 use an attribute and a filter together, and then to inject dependencies into the filter .属性添加元数据,元数据决定是否应用过滤器,过滤器接收注入(inject)的依赖。

How to use dependency injection with an attribute?

这样做的理由很少。

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

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

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();
    }
}

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

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
    }
}

使用可以接收依赖项的公共(public) setter 创建一个属性。

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;
    }
}

将属性应用于 Controller 或操作。

using Microsoft.AspNetCore.Mvc;

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

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

关于c# - 如何使用属性的依赖注入(inject)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4102138/

相关文章:

c# - 如何调用带参数的方法?

c# - WinPcap 过滤器字符串语法错误

c# - 定义两个可为 null 的隐式运算符时无法将 null 转换为 struct

c# - MVC 5 IValidatableObject 不显示错误消息?

asp.net - 从 MVC .Net 中的另一个 View 调用 View

javascript - 在 Razor 语法中嵌入javascript变量

c# - 从外部托管的应用程序和数据库导出数据

c# - Pubnub 执行同步请求

java - 将域对象映射到 Java 中的 Web 服务代理对象

asp.net-mvc - MVC View 问题