c# - 无法从派生自 ActionFilterAttribute 的类访问存储库(或 DbContext)

标签 c# asp.net-core asp.net-core-2.2

我有一个使用存储库模式的 ASP.NET Core 2.2 MVC Web 应用程序。我创建了一个名为 LogAttribute 的类,该类派生自 ActionFilterAttribute这样我就可以在执行 Controller 操作后记录信息。

以下是在 mvc Controller 类中使用此操作过滤器属性的示例:

public class HomeController : Controller
{
    private readonly IMyRepository _repository;

    public HomeController(IMyRepository repository)
    {
        _repository = repository;
    }

    [Log("Go to Home Page")]
    public async Task<IActionResult> Index()
    {
        ...
    }

    [Log("Go to About Page")]
    public async Task<IActionResult> About()
    {
        ...
    }
}

因此,当我转到 /Home 时,它应该记录“转到主页”。当我转到 /About 页面时,它应该记录“转到关于页面”。

但是,我不知道如何从 LogAttribute 类访问我的存储库。这是 LogAttribute 类:

public class LogAttribute : ActionFilterAttribute
{
    private IDictionary<string, object> _arguments;
    private IMyRepository _repository;

    public string Description { get; set; }

    public LogAttribute(string description)
    {
        Description = description;
    }

    // // Injecting repository as a dependency in the ctor DOESN'T WORK
    // public LogAttribute(string description, IMyRepository repository)
    // {
    //     Description = description;
    //     _repository = repository;
    // }

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        _arguments = filterContext.ActionArguments;
        base.OnActionExecuting(filterContext);
    }

    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        var description = Description;

        // NullReferenceException since I don't know
        // how to access _repository from this class
        _repository.AddLog(new LogAction
        {
            Description = description
        });
    }
}

所以我的问题是如何从我的 LogAttribute 类访问我的存储库(或至少是我的 DbContext)?

最佳答案

你不知道。属性不能具有构造函数注入(inject)参数,并且它们的生命周期是无限制的,这使得它们成为与 ASP.NET Core 管道集成的非常糟糕的选择。

因此,属性本身不应该执行任何“繁重的工作”。我觉得各种在线教程和指南在 ActionFilterAttribute 中显示了简单的日志记录(使用 Debug.WriteLine),这对读者来说是一种伤害(例如(不要这样做这个!) https://www.tutorialsteacher.com/mvc/action-filters-in-mvc)

如果您使用的是 ASP.NET Core,则分别实现 IActionFilter(或 IAsyncActionFilter)和 IFilterFactory 并创建 IFilterFactory Attribute(而不是 IActionFilter),如下所示:

// This class is the attribute. Note that it is not an action filter itself.
// This class cannot have DI constructor injection, but it can access the IServiceProvider.
public class LogAttribute : Attribute, IFilterFactory
{
    public IFilterMetadata CreateInstance(IServiceProvider serviceProvider)
    {
        return serviceProvider.GetService<LogFilter>();
    }
}


// This class is the actual filter. It is not an attribute.
// This class *can* have DI constructor injection.
public class LogFilter : IActionFilter // or IAsyncActionFilter
{
    public LogFilter( DbContext db )
    {

    }
}

完整示例可在此处找到:( https://www.devtrends.co.uk/blog/dependency-injection-in-action-filters-in-asp.net-core )

关于c# - 无法从派生自 ActionFilterAttribute 的类访问存储库(或 DbContext),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58244850/

相关文章:

c# - 是否有 WebDriver Navigated 事件?

asp.net-core - 为什么我看不到来自 Serilog 的控制台日志?

c# - 如何在 ASP.NET Core 2.2 项目中为子域正确启用 CORS?

c# - 将区域文件夹中的页面设置为asp.net core 2.2 MVC中的默认页面

c# - 将字符串数组转换为小写

c# - 将字符串在字符串数组中的特定位置分组

c# - 使用 Entity Framework 和 LDAP 的 Oracle 连接字符串

asp.net-web-api - 在同一个解决方案中测试 WebAPI 和前端?

c# - 使用 NLog 在 ASP.NET Core 中记录异常

c# - 如何从第二个 API 调用返回相同的状态代码