【问题标题】:How to Add Logging to MVC4 WebApi如何将日志记录添加到 MVC4 WebApi
【发布时间】:2012-07-10 08:53:21
【问题描述】:

我正在尝试在ApiController 上为Get() 创建一个[LoggedApiCall] 过滤器 据此:ASP.NET Web API ActionFilter example

我创建了一个System.Web.HttpFilters.ActionFilterAttribute。 覆盖允许OnActionExecuted(HttpActionExecutedContext actionExecutedContext)

我似乎找不到从HttpActionExecutedContext 获取调用者IP 的方法

也许我要以错误的方式记录每个 API 调用?

【问题讨论】:

    标签: asp.net-mvc asp.net-mvc-4 asp.net-web-api


    【解决方案1】:

    我们使用添加到HttpConfiguration.Filters 的以下过滤器。一些代码:

    internal class LoggingFilter : IExceptionFilter, IActionFilter
    {
        private readonly ILog log;
    
        public LoggingFilter(ILog log)
        {
            if (log == null)
            {
                throw new ArgumentNullException("log");
            }
    
            this.log = log;
        }
    
        public bool AllowMultiple
        {
            get { return false; }
        }
    
        Task IExceptionFilter.ExecuteExceptionFilterAsync(HttpActionExecutedContext actionContext, CancellationToken cancellationToken)
        {
            if (actionContext == null)
            {
                throw new ArgumentNullException("actionContext");
            }
    
            this.log.Error(string.Format("Unexpected error while executing {0}", this.BuildLogEntry(actionContext.ActionContext)), actionContext.Exception);
            return TaskHelpers.Completed();
        }
    
        Task<HttpResponseMessage> IActionFilter.ExecuteActionFilterAsync(HttpActionContext actionContext, CancellationToken cancellationToken, Func<Task<HttpResponseMessage>> continuation)
        {
            if (actionContext == null)
            {
                throw new ArgumentNullException("actionContext");
            }
    
            if (continuation == null)
            {
                throw new ArgumentNullException("continuation");
            }
    
            if (!this.log.IsDebugEnabled)
            {
                // no point running at all if logging isn't currently enabled
                return continuation();
            }
    
            string logEntry = this.BuildLogEntry(actionContext);
            IDisposable logContext = this.log.DebugTiming("Executing {0}", logEntry);
    
            Task<string> requestContent;
            if (actionContext.Request.Content != null)
            {
                requestContent = actionContext.Request.Content.ReadAsStringAsync().ContinueWith(requestResult => string.IsNullOrEmpty(requestResult.Result) ? "N/A" : requestResult.Result);
            }
            else
            {
                requestContent = TaskHelpers.FromResult("N/A");
            }
    
            return requestContent.ContinueWith(
                requestResult =>
                    {
                        this.log.DebugFormat("{0}, Request = {1}", logEntry, requestResult.Result);
    
                        return continuation()
                            .ContinueWith(t =>
                                {
                                    Task<string> responseContent;
                                    if (t.IsCompleted && t.Result.Content != null)
                                    {
                                        responseContent = t.Result.Content.ReadAsStringAsync().ContinueWith(responseResult => string.IsNullOrEmpty(responseResult.Result) ? "N/A" : responseResult.Result);
                                    }
                                    else
                                    {
                                        responseContent = TaskHelpers.FromResult("N/A");
                                    }
    
                                    return responseContent.ContinueWith(
                                        responseResult =>
                                            {
                                                using (logContext)
                                                {
                                                    this.log.DebugFormat("{0}, Status Code: {1}, Response = {2}", logEntry, t.Result.StatusCode, responseResult.Result);
                                                }
    
                                                return t.Result;
                                            });
                                }).Unwrap();
                    }).Unwrap();
        }
    
        /// <summary>
        /// Builds log data about the request.
        /// </summary>
        /// <param name="actionContext">Data associated with the call</param>
        private string BuildLogEntry(HttpActionContext actionContext)
        {
            string route = actionContext.Request.GetRouteData().Route.RouteTemplate;
            string method = actionContext.Request.Method.Method;
            string url = actionContext.Request.RequestUri.AbsoluteUri;
            string controllerName = actionContext.ActionDescriptor.ControllerDescriptor.ControllerName;
            string actionName = actionContext.ActionDescriptor.ActionName;
    
            return string.Format("{0} {1}, route: {2}, controller:{3}, action:{4}", method, url, route, controllerName, actionName);
        }
    }
    

    我们使用 log4net,您可以将 ILog 实现替换为您认为合适的任何内容。 ILog.DebugTiming 只是一个扩展方法,它使用秒表来获取每次通话的经过时间。

    编辑: 这个帖子Get the IP address of the remote host详细介绍了如何获取远程调用者的IP地址。

    干杯, 院长

    【讨论】:

    • 您发送的链接有效: private string GetClientIp(HttpRequestMessage request) { if (request.Properties.ContainsKey("MS_HttpContext")) { return ((HttpContextWrapper)request.Properties["MS_HttpContext"]) .Request.UserHostAddress; } if (request.Properties.ContainsKey(RemoteEndpointMessageProperty.Name)) { RemoteEndpointMessageProperty prop; prop = (RemoteEndpointMessageProperty)request.Properties[RemoteEndpointMessageProperty.Name];返回道具.地址; } 返回空值; }
    • 看起来 Mike 的答案是更好的选择 - 如果需要,您可以在其中注入实际的日志记录实现,甚至是内置的 web api 日志框架(从而防止工作量加倍)。
    • 我们调查了ITraceWriter 位,但似乎很难关联开始和结束时间,而且社区中似乎明显缺乏生产能力实现来指导自己编写。我们认为上述方法更简单。
    • 既然 ASP.NET 团队已经发布了 ITraceWriter 的参考实现,我强烈建议人们不要使用这个答案 - 使用 nuget.org/packages/Microsoft.AspNet.WebApi.Tracing 的 NuGet 包或编写自定义基于aspnetwebstack.codeplex.com/SourceControl/changeset/view/… 的代码实现
    • @DeanWard:很抱歉热身,但我是否正确,两种解决方案都不能记录实际的逐字请求?即使是跟踪编写器也只是公开了常规的、不可回退的流,所以我没有机会阅读请求内容,对吗?
    猜你喜欢
    • 2018-02-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-15
    相关资源
    最近更新 更多