【问题标题】:Pass Objects to ActionFilter Constructor in MVC C#在 MVC C# 中将对象传递给 ActionFilter 构造函数
【发布时间】:2020-07-22 02:13:57
【问题描述】:

我正在尝试在我的 MVC 应用程序中创建自定义日志过滤器。以下是我的代码

public class LoggerAttribute: ActionFilterAttribute
    {

        private readonly IHttpLogService _httpLogService;
        private readonly ILogService _logService;
        public LoggerAttribute(IHttpLogService httpLogService, ILogService logService)
        {
            _httpLogService = httpLogService;
            _logService = logService;
        }

        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            LogDetails(filterContext);
        }

        private void LogDetails(ActionExecutingContext filterContext)
        {
            try
            {
                HttpLogService httpService = new HttpLogService();
                var httplogger = new LogMetaData()
                {
                    RequestParams = filterContext,
                    ResponseParams  = filterContext
                };
                _httpLogService.Emit("source", "", "Name", httplogger);
            }
            catch (Exception ex)
            {
                _logService.Emit("Error", "token", "Error encountered while trying to execute the request.", ex);
                throw new Exception("An error occurred. Please try again later.");
            }
        }
    }

在上面的代码中,我试图将服务实例传递给我的过滤器属性。如何实现将实例传递给我的自定义过滤器属性?

【问题讨论】:

  • 我已经编辑了上述问题。最后两行已编辑。请帮我举个例子

标签: c# asp.net-mvc action-filter custom-action-filter asp.net-mvc-filters


【解决方案1】:

我之前在一个 ASP.NET MVC 项目中使用 Ninject for DI 进行了此操作。 Andrew 在 4 月 10 日对他自己的回答发表的评论是正确的方向,但这可能对您来说是这样的(示例使用 Ninject,但您可以适应您使用的任何 DI)。

  1. 从技术上讲,您的属性是可以的,但作为实践,您应该定义一个没有行为 的属性,该属性仅与行为所在的过滤器 相关联。我已对您的方法进行了调整以适应此最佳实践,如下所示:
public class LoggerAttribute : ActionFilterAttribute {}

public class LoggerFilter : IActionFilter
{

    private readonly IHttpLogService _httpLogService;
    private readonly ILogService _logService;
    public LoggerAttribute(IHttpLogService httpLogService, ILogService logService)
    {
        _httpLogService = httpLogService;
        _logService = logService;
    }

    // Code removed for brevity
}
  1. 在 Global.asax.cs 中,您需要实例化您的服务(如果有的话,也可以从工厂获取一个)。
namespace MyApp.Web
{
    public class MvcApplication : NinjectHttpApplication
    {
        private static readonly IHttpLogService _httpLogService = someFactory.GetLogService();
        // Or if you don't use a factory
        // private static readonly IHttpLogService _httpLogService = new MyLogServiceImplementation();
        private static readonly ILogService _logService = new MyLogService();

        // Other stuff like OnApplicationStarted() here

        protected override IKernel CreateKernel()
        {
            var kernel = new StandardKernel();
            kernel.BindFilter<LoggerFilter>(FilterScope.Action, 0)
                .WhenActionMethodHas<LoggerAttribute>()
                .WithConstructorArgument("httpLogService", _httpLogService)
                .WithConstructorArgument("logService", _logService);
        }
    }
}

关键部分是我们 .WithConstructorArgument() 的位置,语法会因 DI 包而异。

另请参阅我关于类似问题/结构的更详细回答 here

【讨论】:

    【解决方案2】:

    添加公共属性并将它们设置在属性中,例如此处的 Name 属性:

    [DeserializeAs(Name = "MAIL")]
    

    这样:

    public class LoggerAttribute: ActionFilterAttribute
    {
    
        private readonly IHttpLogService _httpLogService;
        private readonly ILogService _logService;
        public LoggerAttribute(IHttpLogService httpLogService, ILogService logService)
        {
            _httpLogService = httpLogService;
            _logService = logService;
        }
    
        public string CustomProperty { get; set; }
    
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            LogDetails(filterContext);
        }
    
        private void LogDetails(ActionExecutingContext filterContext)
        {
            try
            {
                HttpLogService httpService = new HttpLogService();
                var httplogger = new LogMetaData()
                {
                    RequestParams = filterContext,
                    ResponseParams  = filterContext
                };
                _httpLogService.Emit("source", "", "Name", httplogger);
            }
            catch (Exception ex)
            {
                _logService.Emit("Error", "token", "Error encountered while trying to execute the request.", ex);
                throw new Exception("An error occurred. Please try again later.");
            }
        }
    }
    

    并设置它:

    [Logger(CustomProperty="YourValue")]
    

    【讨论】:

    • '[DeserializeAs(Name = "MAIL")]' 是关于什么的?我必须在哪里使用它??
    • 我希望你有我的问题。基本上,我试图将服务实例传递给过滤器属性。那么,如何在上面的代码中将服务实例传递给我的过滤器属性?
    • 对不起,我误会你了。我认为您应该在属性构造函数中使用您的 DI 手动解决它。
    猜你喜欢
    • 2014-06-04
    • 1970-01-01
    • 2019-08-07
    • 2016-02-15
    • 2017-03-17
    • 1970-01-01
    • 2012-07-09
    • 2011-10-24
    • 1970-01-01
    相关资源
    最近更新 更多