2012-07-10 9 views
19

Próbuję utworzyć [LoggedApiCall] filtr dla Get() na ApiController Zgodnie z tym: ASP.NET Web API ActionFilter exampleJak dodać Logowanie do MVC4 WebAPI

Stworzyłem System.Web.HttpFilters.ActionFilterAttribute. Korekcja umożliwia OnActionExecuted(HttpActionExecutedContext actionExecutedContext)

I nie wydają się znaleźć sposób, aby uzyskać adres IP rozmówcy z HttpActionExecutedContext

Może mam zamiar o zalogowaniu każdy API zadzwonić w niewłaściwy sposób?

Odpowiedz

13

Używamy następującego filtra, który dodajemy do HttpConfiguration.Filters. Niektóre kodu:

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

Używamy log4net, można zastąpić realizację ILog z tym, co uważasz. ILog.DebugTiming to tylko metoda rozszerzenia, która wykorzystuje stoper, aby uzyskać czas, jaki upłynął dla każdego połączenia.

Edytuj: Ten wpis Get the IP address of the remote host zawiera szczegółowe informacje na temat uzyskiwania adresu IP zdalnego wywołującego.

Cheers, Dean

+0

Link został wysłany prace: prywatną GetClientIp string (HttpRequestMessage żądanie) \t \t { \t \t \t if (request.Properties.ContainsKey ("MS_HttpContext")) \t \t \t { \t \t \t \t return ((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 podpory; \t \t \t \t prop = (RemoteEndpointMessageProperty) request.Properties [RemoteEndpointMessageProperty.Name]; \t \t \t \t return prop.Adress; \t \t \t} \t \t \t return null; \t \t} – maxfridbe

+0

Wygląda na to, że odpowiedź Mike'a jest lepszym wyborem - gdzie można wstrzyknąć rzeczywistą implementację rejestrowania, a nawet wbudowaną architekturę sieci web api, jeśli jest to pożądane (i tym samym zapobiec podwojeniu wysiłku). – Lex

+0

Badaliśmy bity "ITraceWriter", ale wydaje się, że bardzo trudno jest skorelować czasy początku i końca i wydaje się, że istnieje wyraźny brak implementacji siły produkcyjnej w społeczności, aby prowadzić własne. Uznaliśmy, że powyższe podejście jest prostsze. –

Powiązane problemy