Get back Request Body within ActionFilter - c#

For logging purposes, I am trying to monitor the requests being made through a WebAPI. I have created and I am looking for a way to get back the body sent through in a request after the request has been fulfilled and responded to. I am trying to do this through using a ActionFilter but thus far have failed in reading the body from the request.
Can anybody give some advice how I may access this information?
For context I am trying to do this within this code:
public class LoggingActionFilter : ActionFilterAttribute
{
public override Task OnActionExecutedAsync(HttpActionExecutedContext actionExecutedContext, CancellationToken cancellationToken)
{
var test = actionExecutedContext.Request.Content.ReadAsStringAsync().Result;
return base.OnActionExecutedAsync(actionExecutedContext, cancellationToken);
}
}
I have tried reading back the Content on the actionExecutedContext variable in order to get back the body but have found this to return just blank so far.

you're just dealing with request body so don't need to use OnActionExecutedAsync method, you can just override OnActionExecuting like this,
public override void OnActionExecuting(HttpActionContext actionContext)
{
var test = (actionContext.Request.Content as ObjectContent).Value.ToString();
// your logging code here
}
Another option available in WebAPI is DelegatingHandler. if you want to log just request body then override SendAsync method,
public class ApiLogHandler : DelegatingHandler
{
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
CancellationToken cancellationToken)
{
var requestBody = request.Content.ReadAsStringAsync().Result;
// your logging code here
return base.SendAsync(request, cancellationToken);
}
}
If you decided to choose DelegatingHandler then you need to register that handler to Global message handlers.

Related

ASP.NET WebAPI 2 - MessageHandler return response before logging

I have implemented some logging in WebAPI 2 via a MessageHandler.
It seems to me that the response is returned only AFTER the logging occurs. It would be nice for the user to receive their response, but for the logging to be an after thought. Is this possible?
public abstract class MessageHandler : DelegatingHandler
{
protected HttpRequestMessage requestMessage;
protected HttpResponseMessage responseMessage;
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage requestMessage, CancellationToken token)
{
var requestTime = DateTime.Now;
this.requestMessage = requestMessage;
responseMessage = await base.SendAsync(requestMessage, token);
var responseTime = DateTime.Now;
await LogEntryAsync(requestTime, responseTime);
return responseMessage;
}
protected abstract Task LogEntryAsync(DateTime requestTime, DateTime responseTime);
}
Yes, of course, it's possible.
The usual way to handle this is to place the message in a concurrent queue consumed by a thread that deals with logging from all sources.
The thread and the queue would be encapsulated inside a Logger class with an interface similar to:
public class ILog
{
void Debug(....);
void Info(....);
void Warning(....);
}
and your code would look like:
ILog Log {get; set;}
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage requestMessage, CancellationToken token)
{
var requestTime = DateTime.Now;
this.requestMessage = requestMessage;
responseMessage = await base.SendAsync(requestMessage, token);
var responseTime = DateTime.Now;
log.Info(requestTime, responseTime); // No async needed
return responseMessage;
}
Blocking (for say database or file logs) would then occur on the consumer thread instead of the main thread that handles the user HTTP session.
The real question is why would you want to implement this yourself when several widely available libraries already do it for you and better than you would hope to achieve without spending a prohibitive amount of time on a comprehensive log solution (see NLog, Log4Net, CommonLogging).

Intercept C# HttpClient GetAsync

I have a web project (C#, MVC5 but no WebAPI) and a simple HTTP REST client that is calling an external REST service and acquires an accessToken etcing.
I want to check the response from all my Get/PostAsync calls for statusCode 401 but I see that I can only override the SendAsync method when implementing the DelegatingHandler.
class CustomDelegatingHandler : DelegatingHandler
{
async protected override Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request, CancellationToken cancellationToken)
{
HttpResponseMessage response = await base.SendAsync(request, cancellationToken);
if (response.StatusCode == HttpStatusCode.Unauthorized)
{
Is there something else I can do so as not to change the implementation of all my async calls to use SendAsync?
(What I really really want to do is refresh the accessToken.)
I think you're on the right track. You wouldn't need to change your calls to use SendAsync instead of GetAsync, PostAsync, etc though. Rather, you'd need to change how you instantiate HttpClient:
var client = new HttpClient(new CustomDelegatingHandlerTokenRefresher());
// GetAsync, PostAsync, etc will hit your handler
Use the Decorator or Interceptor pattern.
Example concrete decorator:
public class CustomDelegatingHandlerTokenRefresher : DelegatingHandler
{
public CustomDelegatingHandlerTokenRefresher(DelegatingHandler handler)
{
InnerHandler = handler;
}
protected override async Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request, CancellationToken cancellationToken)
{
RefreshToken();
return await InnerHandler.SendAsync(request, cancellationToken);
}
}

Better way to determine API Endpoint in DelegatingHandler than string compare?

I am working on a WebAPI project, and have a custom MessageHandler class inheriting from DelegatingHandler. If a request is aimed at a specific controller endpoint, I need to do something different than all other requests.
My question is: Is there a better way to accomplish this than by string comparison against the RequestUri?
public class CustomMessageHandler : DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
if (request.Method == HttpMethod.Get
&& request.RequestUri.Segments.Last().Trim('/').Equals("Session", StringComparison.CurrentCultureIgnoreCase))
...
}
}
Feels clunky to me, but I have not yet been able to find a better method than the above.

No Response Header in DelegatingHandler

I'm trying to log the HTTP Response Headers of my Web API project.
The project is developed by VS2012, .NET 4.5 and ASP.NET MVC 4.
I've wrote a DelegatingHandler subclass like this:
public class LoggingHandler : DelegatingHandler
{
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
// Execute the request
return base.SendAsync(request, cancellationToken).ContinueWith(task =>
{
var response = task.Result;
return response;
});
}
}
However, the problem is, I can't get the header values from the response. response.Headers is an empty collection, response.Content.Headers contains nothing but a key named Content-Type, and HttpContext.Current is null.
I've seen the code of WebAPIContrib which use the same logic to log the headers, but their code does not seem to work either.
So how should I trace the HTTP Response Headers in Web API project?
Message handlers are called in the same order that they appear in
MessageHandlers collection. Because they are nested, the response
message travels in the other direction. That is, the last handler is
the first to get the response message.
Make sure that the logging handler is registered early in the pipeline. Preferably first.
public static class WebApiConfig {
public static void Register(HttpConfiguration config) {
config.MessageHandlers.Add(new LoggingHandler(...));
//...add other handlers
config.MessageHandlers.Add(new MessageHandler1());
config.MessageHandlers.Add(new MessageHandler2());
// Other code not shown...
}
}
That way any other handlers would have their chance to populate the response and have that info logged.
You can also simplify the class using async/await syntax to make accessing the response cleaner.
public class LoggingHandler : DelegatingHandler {
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) {
//...Extract and log request
LogRequest(request);
// Send the request on to the inner handler(s) and get the response
var response = await base.SendAsync(request, cancellationToken);
//...Extract details from response for logging
LogResponse(response);
return response;
}
private void LogRequest(HttpRequestMessage request) {
//... code removed for brevity
}
private void LogResponse(HttpResponseMessage response) {
//... code removed for brevity
}
}
Should be able to access the necessary details from the response before returning it.
Reference : HTTP Message Handlers in ASP.NET Web API
Try out the below code.
return base.SendAsync(request, cancellationToken).ContinueWith(
task =>
{
var headers = task.Result.ToString();
var body = task.Result.Content.ReadAsStringAsync().Result;
// RETURN THE ORIGINAL RESULT
var response = task.Result;
return response;
}
);
You must look at the right place:
request.Content.Headers.ContentType
Assuming there's a Content-Type: application/json request header, then the aforementioned will return "application/json".
So basically some headers are associated with the Content and that's where you should be reading them from.
Same is true for the response headers. Depending on their type you might need to extract them from the response content (for requests that return body)
response.Content.Headers.ContentType

How to mock(rhino.mocks) response object from base.SendAsync() in MVC4.5 Web API handler SendAsync() method

I have to write unit test on ASP.NET MVC Web API Controller with Rhino.Mock
I have a handler named AHandler.cs with inherts from System.Net.Http.HttpClientHandler class.
The singnature SendAsync method of AHandler.cs is like followings :
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
.....
var response = base.SendAsync(request, cancellationToken).Result;
if (response.IsSuccessStatusCode)
{
.....
}
}
the base keyword above means HttpClientHandler and its SendAsync() method is "protected"!!!
Now I try to mock the object "base.SendAsync(request, cancellationToken).Result" and got the hand-made response result I wanted.
But it seems that Rhino mocks can't see the "base" keyword when I wrote the followings code :
var mockbase = MockRepository.GenerateMock<AHandler>;
mockbase.Stub(x => x.base <=== can't see base keyword
^^^^^
So I change another way and try to mock the HttpClientHandler class
var mockbase = MockRepository.GenerateMockHttpClientHandler>;
mockbase.Stub(x => x. <== I can't see SendAsync() method, becase it is protected !!
Now I really suffer in it !!
Can anybody give me some advice that how to made a custom response in MVC handler ?!
very thanks !!
Why do you want to mock a handler in first place ? You can inject an specific dummy implementation for your tests. That handler will return a new HttpResponse message expected by your tests.
public class MyDummyHttpHandler : DelegatingHandler
{
HttpResponseMessage response;
public MyDummyHttpHandler(HttpResponseMessage response)
{
this.response = response;
}
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
.....
TaskCompletionSource<HttpResponseMessage> tsc = new TaskCompletionSource<HttpResponseMessage>();
tsc.SetResult(this.response);
return tsc.Task;
}
}

Categories

Resources