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.
Related
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).
I have a default CustomAuthorizeAttribute defined in my Web Api project.
config.Filters.Add(new CustomAuthorizeAttribute());
However I have a special Controller where I would like to use a SpecialAuthorizeAttribute.
[SpecialAuthorize]
public class MySpecialController : ApiController
In the Asp.Net vNext we have a new attribute to override the default filters, but how could I make it work in the Web Api 2?
Edit 1:
One possible (but not ideal) solution is make the CustomAuthorizeAttribute check if there's another AuthorizeAttribute in the scope of the Controller or Action. In my case I have only the SpecialAuthorizeAttribute so:
public class CustomAuthorizeAttribute : AuthorizeAttribute
{
public override void OnAuthorization(System.Web.Http.Controllers.HttpActionContext actionContext)
{
if (actionContext.ControllerContext.ControllerDescriptor.GetCustomAttributes<SpecialAuthorizeAttribute>().Any() || actionContext.ActionDescriptor.GetCustomAttributes<SpecialAuthorizeAttribute>().Any())
{
return;
}
base.OnAuthorization(actionContext);
}
public override System.Threading.Tasks.Task OnAuthorizationAsync(System.Web.Http.Controllers.HttpActionContext actionContext, System.Threading.CancellationToken cancellationToken)
{
return base.OnAuthorizationAsync(actionContext, cancellationToken);
}
}
You can use OverrideAuthenticationAttribute.
As you can this answer this attribute is used to suppress global authentication filters.
OverrideAuthorization attribute is the exact fit (in ASP.NET Web API 2) for your requirement. You can find its usage and purpose in simple terms in this article.
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);
}
}
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.
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;
}
}