2012-07-10 71 views
19

我想上ApiController 創建一個Get()一個[LoggedApiCall]過濾器根據這一點:ASP.NET Web API ActionFilter example如何記錄添加到MVC4的WebAPI

我創建了一個System.Web.HttpFilters.ActionFilterAttribute。 的倍率允許OnActionExecuted(HttpActionExecutedContext actionExecutedContext)

我似乎無法找到一種方法,從HttpActionExecutedContext

也許我會有關記錄每個API調用錯誤的方式獲得致電者的IP?

回答

13

我們使用下面的過濾器,我們添加到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地址。

乾杯, 院長

+0

你發送的作品的鏈接: 私人字符串GetClientIp(HttpRequestMessage要求) \t \t { \t \t \t如果(request.Properties.ContainsKey( 「MS_HttpContext」)) \t \t \t {(HttpContextWrapper)request.Properties [「MS_HttpContext」])。Request.UserHostAddress; \t \t \t} \t \t \t如果(request.Properties.ContainsKey(RemoteEndpointMessageProperty.Name)) \t \t \t { \t \t \t \t RemoteEndpointMessageProperty丙; \t \t \t \t prop =(RemoteEndpointMessageProperty)request.Properties [RemoteEndpointMessageProperty.Name]; \t \t \t \t return prop.Address; \t \t \t} \t \t \t return null; \t \t} – maxfridbe 2012-07-10 21:52:19

+0

看起來好像Mike的回答是更好的選擇 - 如果需要的話可以注入實際的日誌記錄實現甚至內置的web api日誌框架(從而防止加倍努力)。 – Lex 2012-08-28 08:32:27

+0

我們調查了'ITraceWriter'位,但它似乎很難將開始和結束時間關聯起來,並且在社區中似乎明顯缺乏生產力實施來指導您編寫自己的。我們決定上述方法更簡單。 – 2012-08-28 12:33:07