2012-07-10 5 views
19

Ich versuche, einen [LoggedApiCall] Filter für ein Get() auf einem ApiController Nach dieser zu erstellen: ASP.NET Web API ActionFilter exampleWie Protokollierung In der MVC4 WebAPI

ich geschaffen habe ein System.Web.HttpFilters.ActionFilterAttribute. Die Überschreibung ermöglicht OnActionExecuted(HttpActionExecutedContext actionExecutedContext)

Ich kann nicht scheinen, einen Weg zu finden, um die IP-Adresse des Anrufers aus dem HttpActionExecutedContext

Vielleicht bekommen ich gehe über jede API-Aufruf falsch Protokollierung?

Antwort

13

Wir verwenden den folgenden Filter, den wir zu HttpConfiguration.Filters hinzufügen. Einige Code:

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); 
    } 
} 

Wir verwenden log4net, können Sie die ILog Implementierung ersetzen mit dem, was Sie für richtig halten. ILog.DebugTiming ist nur eine Erweiterungsmethode, die eine Stoppuhr verwendet, um die verstrichene Zeit für jeden Anruf abzurufen.

Edit: Dieser Beitrag Get the IP address of the remote host enthält Details, wie Sie die IP-Adresse des Remote-Aufrufers erhalten.

Cheers, Dean

+0

Der Link funktioniert gesendet: privat string GetClientIp (HttpRequestMessage Anfrage) \t \t { \t \t \t if (request.Properties.ContainsKey ("MS_HttpContext")) \t \t \t { \t \t \t \t Rückgabe ((HttpContextWrapper) request.Properties ["MS_HttpContext"]). Request.UserHostAddress; \t \t \t} \t \t \t if (request.Properties.ContainsKey (RemoteEndpointMessageProperty.Name)) \t \t \t { \t \t \t \t RemoteEndpointMessageProperty prop; \t \t \t \t prop = (RemoteEndpointMessageProperty) request.Properties [RemoteEndpointMessageProperty.Name]; \t \t \t \t Rückgabe prop.Address; \t \t \t} \t \t \t zurück null; \t \t} – maxfridbe

+0

Es scheint wie Mike Antwort ist die bessere Wahl - wo Sie die eigentliche Logging-Implementierung oder sogar das integrierte Web-API-Framework, wenn gewünscht (und damit eine Verdoppelung der Aufwand) injizieren können. – Lex

+0

Wir haben die "ITraceWriter" -Bits untersucht, aber es schien sehr schwierig zu sein, Anfangs- und Endzeiten zu korrelieren, und es scheint einen deutlichen Mangel an Implementierungen der Produktionsstärke in der Community zu geben, um das eigene zu steuern. Wir entschieden, dass der obige Ansatz einfacher war. –

Verwandte Themen