c# - Asp.net Core 自定义过滤器实现 IActionModelConvention 和 IFilterFactory

标签 c# asp.net-core asp.net-core-mvc asp.net-core-2.1 custom-action-filter

我需要创建一个实现 IActionModelConventionIFilterFactory 的自定义操作过滤器。

我使用 IActionModelConvention 同时设置多个路由,我使用 IFilterFactory 注入(inject)一些我需要使用的服务。

问题IActionModelConvention 中的Apply() 方法在CreateInstance() 之前被调用> 来自 IFilterFactory 的方法,我需要注入(inject)的服务在 Apply() 中可用。

我的问题 是如何在调用 Apply() 方法之前注入(inject)服务?而且我也更喜欢使用 IFilterFactory 来注入(inject)服务,因为它不会强制我用 [ServiceFilter][TypeFilter]属性。

这是我的代码:

public class Contains2RoutesAttribute : Attribute, IActionModelConvention, IFilterFactory
{
    public ISomeService SomeService{ get; set; }

    public IFilterMetadata CreateInstance(IServiceProvider serviceProvider)
    {
        ISomeService someService = serviceProvider.GetService<ISomeService>();
        return new Contains2RoutesAttribute() { SomeService = someService };
    }

    public void Apply(ActionModel action)
    {
        // Here I need to use the service injected:
        this.SomeService.DoSomething(); // ERROR: The service here is null.

        action.Selectors.Clear();

        // Adding route 1:
        action.Selectors.Add(new SelectorModel
        {
            AttributeRouteModel = new AttributeRouteModel { Template = "~/index1" }
        });

        // Adding route 2:
        action.Selectors.Add(new SelectorModel
        {
            AttributeRouteModel = new AttributeRouteModel { Template = "~/index2" }
        });
    }
}

最佳答案

您的 IActionModelConvention 实现只会在启动时运行一次。 Apply 将为每个操作调用一次。要在 Apply 函数内部使用 ISomeService,请将其作为构造函数参数传递。您的 Contains2RoutesAttribute 类不必是 IFilterFactory 的属性或实现,因为您已在评论中确认它不参与 filter pipeline .这是一个代码示例,其中我还重命名了该类以更好地表示它在做什么(它不再是一个属性):

public class Contains2RoutesConvention : IActionModelConvention
{
    private readonly ISomeService someService;

    public Contains2RoutesConvention(ISomeService someService)
    {
        this.someService = someService;
    }

    public void Apply(ActionModel actionModel)
    {
        someService.DoSomething();

        ...
    }
}

Startup.ConfigureServices 中注册此约定:

services.AddMvc(options =>
{
    options.Conventions.Add(new Contains2RoutesConvention(new SomeService()));
});

这是它变得更有趣的地方。您不能将依赖注入(inject)与 convention 一起使用,所以在这个例子中,我在构造 Contains2RoutesConvention 时内联创建了一个 SomeService 的实例。如果你希望这个实例是一个可以在你的应用程序的其他地方使用的单例,你可以在 ConfigureServices 中做这样的事情:

var someService = new SomeService();

services.AddMvc(options =>
{
    options.Conventions.Add(new Contains2RoutesConvention(someService));
});

services.AddSingleton<ISomeService>(someService);

当然,这取决于 SomeService 是否有自己的依赖项,但如果有,它们将无法从 DI 容器中解析,因为它在管道中还为时过早。

关于c# - Asp.net Core 自定义过滤器实现 IActionModelConvention 和 IFilterFactory,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53525645/

相关文章:

c# - XML DataTemplate 绑定(bind)多层用户控件

C# - 应用程序在连接网络摄像机后挂起

c# - 在哪里生成 SignInManager IdentityUser .cshtml 文件

angularjs - 带有 Angular CLI 和实时重新加载的 ASP.NET Core

asp.net-core - 修改 MVC 6 的原始 html 输出

c# - CA1303 警告 - 方法将文字字符串作为参数传递

asp.net-core - 有没有办法在.net core类库中使用IHostingEnvironment?

c# - 开发期间安装/卸载 Windows 服务

entity-framework - 将迁移更新到数据库时出现错误 : Foreign key constraint may cause cycles or multiple cascade paths

c# - colorbox 不显示 flickr 画廊集成中的第一个标题