Unit testing Custom MessageHandler - c#

I have a custom handler as below:
public class LoggingHandler : DelegatingHandler
{
public LoggingHandler()
{
}
protected override async Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request,
CancellationToken cancellationToken)
{
var logger = new Logger(new something1(), param2, param3);
logger.LogInformation(
$"Incoming request: {request.Method} {request.RequestUri} );
.
.
.
.
return httpResponse;
}
}
I am familiar with Moq and I am able to moq the request and response message and assert successfully on that.
However as you can see I have a logger initialization done in the SendAsync method and log information regarding request, response and errors.
How can I test the logger in this workflow?.

Problem will be that because of the manual initialization of the logger it is difficult to mock it.
The logger should have been an injected dependency.
public class LoggingHandler : DelegatingHandler {
private readonly ILogger logger;
public LoggingHandler(ILogger logger) {
this.logger = logger;
}
//...
If injection is not an option then have a virtual factory method that can be overridden when testing.
public class LoggingHandler : DelegatingHandler {
public LoggingHandler() {
}
protected virtual ILogger CreateLogger() {
//...
}
protected override async Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request,
CancellationToken cancellationToken) {
var logger = CreateLogger();
logger.LogInformation(
$"Incoming request: {request.Method} {request.RequestUri} );
//....
return httpResponse;
}
//...

Related

Scoped service creating two different instances for a request

I'm fairly new to Asp.Net core 6 and am working on an GraphQL API that receives a bearer token in the request. The API then invokes another Web API and passes the same bearer token in the header. Below is what my code looks like-
Program.cs:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddScoped<HeaderHandler>();
builder.Services.AddScoped<TokenContainer>();
//builder.Services.AddScoped<IFooGateway, FooGateway>();
builder.Services.AddHttpClient<IFooGateway, FooGateway>((c) =>
{
c.BaseAddress = new Uri(builder.Configuration["FooApiUrl"]);
})
.AddHttpMessageHandler<HeaderHandler>();
builder.Services.AddTransient<GraphApiService>();
var app = builder.Build();
app.UseMiddleware<HeaderMiddleware>();
app.MapGraphQL();
app.Run();
HeaderMiddleware.cs
public class HeaderMiddleware
{
//TokenContainer _tokenContainer;
private readonly RequestDelegate _requestDelegate;
public HeaderMiddleware()
{
}
public HeaderMiddleware(RequestDelegate requestDelegate)
{
_requestDelegate = requestDelegate;
//_tokenContainer = tokenContainer;
}
public async Task InvokeAsync(HttpContext context, TokenContainer tokenContainer)
{
var header = context.Request.Headers.Authorization;
tokenContainer.SetToken(header);
await _requestDelegate(context);
}
TokenContainer.cs:
public class TokenContainer
{
public string BearerToken { get; private set; }
public void SetToken(string token) => BearerToken = token;
}
HeaderHandler.cs:
public class HeaderHandler : DelegatingHandler
{
TokenContainer _tokenContainer;
public HeaderHandler()
{
}
public HeaderHandler(TokenContainer tokenContainer)
{
_tokenContainer = tokenContainer;
}
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
// for every request sent via the http client, intercept & add the bearer token header.
request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("bearer", _tokenContainer.BearerToken);
// continue with request pipeline
return await base.SendAsync(request, cancellationToken);
}
}
FooGateway.cs:
public class FooGateway : IFooGateway
{
private readonly HttpClient _httpClient;
private readonly IConfiguration _configuration;
private readonly string _context = String.Empty;
public FooGateway(HttpClient httpClient, IConfiguration configuration)
{
_configuration = configuration;
_context = configuration["FooContext"];
_httpClient = httpClient;
}
public void DoSomething()
{
_httpClient.PostAsync("/blabla");
}
}
So, the idea was that the bearer token for every incoming request will be stored in a class called TokenContainer and the HttpHandler will add it to all the outgoing requests.
However, what is happening is that the token is stored in the TokenContainer but the HeaderHandler gets a different instance of TokenContainer in its constructor with its BearerToken property set to null.
Can someone please explain why the same instance of TokenContainer from the middleware is not being passed into the HeaderHandler?
The issue you are seeing is because the lifetime of the HttpMessageHandler is not the same as the lifetime of the request: usually, the same handler will be reused across many requests and be controlled separately on expiration timers and such.
You should not expect that a service injected into your message handler will be the same object that is injected outside it when it is registered as scoped.
https://andrewlock.net/understanding-scopes-with-ihttpclientfactory-message-handlers/#scope-duration-in-ihttpclientfactory
As the article suggests, to use the same scoped instance as you do outside the handler, you have to rely on IHttpContextAccessor to access the current HttpContext and fetch the service from there. So your handler implementation would look something like this:
public class HeaderHandler : DelegatingHandler
{
IHttpContextAccessor _httpContextAccessor;
public HeaderHandler()
{
}
public HeaderHandler(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var tokenContainer = _httpContextAccessor
.HttpContext
.RequestServices
.GetRequiredService<TokenContainer>();
// for every request sent via the http client, intercept & add the bearer token header.
request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("bearer", tokenContainer.BearerToken);
// continue with request pipeline
return await base.SendAsync(request, cancellationToken);
}
}
This should make sure that the TokenContainer instance is the same across your current request and http calls.
Remember that to add this functionality you need to add the accessor like this:
services.AddHttpContextAccessor();

MediatR cancel publish subsequent messages

My Mediatr is using the SyncContinueOnException publish strategy, is there any way to run some validation before start the propagation?
Example:
_mediatr.Publish(new MyNotification());
public class MyValidationHandler :
INotificationHandler<MyValidationHandler>
{
Task INotificationHandler<MyValidationHandler>.Handle(MyValidationHandler notification, CancellationToken cancellationToken)
{
// STOP propagation if some condition is false
}
}
public class FirstHandlers :
INotificationHandler<MyNotification>
{
Task INotificationHandler<MyNotification>.Handle(MyNotification notification, CancellationToken cancellationToken)
{
Console.WriteLine("x");
return Task.CompletedTask;
}
}
public class SecondHandlers :
INotificationHandler<MyNotification>
{
Task INotificationHandler<MyNotification>.Handle(MyNotification notification, CancellationToken cancellationToken)
{
Console.WriteLine("x");
return Task.CompletedTask;
}
}
Update Sorry, misread this originally!
One way to wrap the MediatR Publish behavior is to decorate the IMediator instance itself, either manually or with a library like Scrutor. You can add a marker interface to identify notifications that should pass through your validation logic, with any other events just flowing through to MediatR.
public class MediatorDecorator : IMediator
{
private readonly IMediator _mediator;
public MediatorDecorator(IMediator mediator)
{
_mediator = mediator;
}
public Task Publish<TNotification>(TNotification notification, CancellationToken cancellationToken = default) where TNotification : INotification
{
if (notification is IValidatableNotification)
{
// Your validation behavior here
return Task.CompletedTask; // if the validation fails, respond as you'd like ...
}
return _mediator.Publish(notification, cancellationToken);
}
// ...
}
And in Startup, after the MediatR registration, using Scrutor's Decorate:
services.AddMediatR(typeof(Startup));
services.Decorate<IMediator, MediatorDecorator>();

Correct usage of IHttpMessageHandlerFactory?

I have a use case for HttpMessageHandler that requires new options on instantiation. I believe that IHttpMessageHandlerFactory.CreateHandler is the correct API here, but I'm not sure if this usage is correct:
public class MyDelegatingHandler : DelegatingHandler {
public MyDelegatingHandler(
HttpMessageHandler internalHandler
)
{
_internalHandler = internalHandler;
}
protected override async Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request,
CancellationToken cancellationToken
)
{
// custom logic
return await _internalHandler.SendAsync(request, cancellationToken).ConfigureAwait(false);
}
private HttpMessageHandler _internalHandler;
}
public class MyHttpClientFactory {
public MyHttpClientFactory(
IHttpMessageHandlerFactory factory
)
{
_factory = factory;
}
public HttpClient CreateClient(
// arguments
)
{
return new HttpClient(
new MyDelegatingHandler(_factory.CreateHandler()),
disposeHandler: false
);
}
private IHttpMessageHandlerFactory _factory;
}
Assuming MyDelegatingHandler has no state that needs to be disposed on its own, will this correctly use the lifetime management features of HttpClientFactory injected through the IHttpMessageHandlerFactory dependency?

Unit Testing methods within which extension methods are used for external resources

I need to Unit test RequestToken method that uses HttpClient and extension method RequestPasswordTokenAsync.
I have got a null reference exception even when a delegatingHandler is passed to the HttpClient.
var delegatingHandler = new DelegatingHandlerStub(false);
var httpClient = new HttpClient(delegatingHandler);
var tokenServices = new TokenServices(httpClient)
tokenServices.RequestToken(passwordTokenRequest); //exception
public class TokenServices : ITokenServices
{
private readonly HttpClient _httpClient;
public TokenServices(HttpClient httpClient)
{
_httpClient = httpClient;
}
public async Task<TokenResponse> RequestToken(PasswordTokenRequest request)
{
var response = await _httpClient.RequestPasswordTokenAsync(request);
}
}
public class DelegatingHandlerStub : DelegatingHandler
{
private readonly Func<HttpRequestMessage, CancellationToken, Task<HttpResponseMessage>> _handlerFunc;
public DelegatingHandlerStub(bool toThrowException)
{
_handlerFunc = (request, cancellationToken) =>
{
if (toThrowException)
throw new Exception();
return Task.FromResult(request.CreateResponse(HttpStatusCode.OK));
};
}
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
return _handlerFunc(request, cancellationToken);
}
}
namespace IdentityModel.Client
{
public static class HttpClientTokenRequestExtensions
{
public static Task<TokenResponse> RequestPasswordTokenAsync(this HttpMessageInvoker client, PasswordTokenRequest request, CancellationToken cancellationToken = default(CancellationToken));
}
}
I have to write a wrapper around HttpClient.
If there are a better solution, please post it here

Decorating ASP.NET Web API IHttpController

I'm trying to wrap Web API controllers (IHttpController implementations) with decorators, but when I do this, Web API throws an exception, because somehow it is expecting the actual implementation.
Applying decorators to controllers is a trick I successfully apply to MVC controllers and I obviously like to do the same in Web API.
I created a custom IHttpControllerActivator that allows resolving decorated IHttpController implementations. Here's a stripped implementation:
public class CrossCuttingConcernHttpControllerActivator : IHttpControllerActivator {
private readonly Container container;
public CrossCuttingConcernHttpControllerActivator(Container container) {
this.container = container;
}
public IHttpController Create(HttpRequestMessage request,
HttpControllerDescriptor controllerDescriptor, Type controllerType)
{
var controller = (IHttpController)this.container.GetInstance(controllerType);
// Wrap the instance in one or multiple decorators. Note that in reality, the
// decorator is applied by the container, but that doesn't really matter here.
return new MyHttpControllerDecorator(controller);
}
}
My decorator looks like this:
public class MyHttpControllerDecorator : IHttpController {
private readonly IHttpController decoratee;
public MyHttpControllerDecorator(IHttpController decoratee) {
this.decoratee = decoratee;
}
public Task<HttpResponseMessage> ExecuteAsync(
HttpControllerContext controllerContext,
CancellationToken cancellationToken)
{
// this decorator does not add any logic. Just the minimal amount of code to
// reproduce the issue.
return this.decoratee.ExecuteAsync(controllerContext, cancellationToken);
}
}
However, when I run my application and request the ValuesController, Web API throws me the following InvalidCastException:
Unable to cast object of type 'WebApiTest.MyHttpControllerDecorator'
to type 'WebApiTest.Controllers.ValuesController'.
Stacktrace:
at lambda_method(Closure , Object , Object[] )
at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.<>c__DisplayClass13.<GetExecutor>b__c(Object instance, Object[] methodParameters)
at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.Execute(Object instance, Object[] arguments)
at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.<>c__DisplayClass5.<ExecuteAsync>b__4()
at System.Threading.Tasks.TaskHelpers.RunSynchronously[TResult](Func`1 func, CancellationToken cancellationToken)
It's just as if Web API supplies us with the IHttpController abstraction but skips it and still depends on the implementation itself. This would of course be a severe violation of the Dependency Inversion principle and make the abstraction utterly useless. So I'm probably doing something wrong instead.
What I'm I doing wrong? How can I happily decorate my API Controllers?
I would say, that the natural, designed way how to achieve this behaviour in ASP.NET Web API is with the Custom Message Handlers / Delegation Handlers
For example I do have this DelegationHandler in place
public class AuthenticationDelegationHandler : DelegatingHandler
{
protected override System.Threading.Tasks.Task<HttpResponseMessage>
SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
// I. do some stuff to create Custom Principal
// e.g.
var principal = CreatePrincipal();
...
// II. return execution to the framework
return base.SendAsync(request, cancellationToken).ContinueWith(t =>
{
HttpResponseMessage resp = t.Result;
// III. do some stuff once finished
// e.g.:
// SetHeaders(resp, principal);
return resp;
});
}
And this is how to inject that into the structure:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.MessageHandlers.Add(new AuthenticationDelegationHandler());
You can work around this by implementing IHttpActionInvoker and "converting" the decorator into the decorated instance at the point that the IHttpController abstraction is no longer relevant.
This is easily done by inheriting from ApiControllerActionInvoker.
(I've hard coded the example and would expect any real world implementation to be more flexible.)
public class ContainerActionInvoker : ApiControllerActionInvoker
{
private readonly Container container;
public ContainerActionInvoker(Container container)
{
this.container = container;
}
public override Task<HttpResponseMessage> InvokeActionAsync(
HttpActionContext actionContext,
CancellationToken cancellationToken)
{
if (actionContext.ControllerContext.Controller is MyHttpControllerDecorator)
{
MyHttpControllerDecorator decorator =
(MyHttpControllerDecorator)actionContext.ControllerContext.Controller;
// decoratee changed to public for the example
actionContext.ControllerContext.Controller = decorator.decoratee;
}
var result = base.InvokeActionAsync(actionContext, cancellationToken);
return result;
}
}
This was registered in Global.asax.cs
GlobalConfiguration.Configuration.Services.Replace(
typeof(IHttpControllerActivator),
new CrossCuttingConcernHttpControllerActivator(container));
GlobalConfiguration.Configuration.Services.Replace(
typeof(IHttpActionInvoker),
new ContainerActionInvoker(container));
Whether you'd actually want to do this is another matter - who knows the ramifications of altering actionContext?
You can provide a custom implementation of IHttpControllerSelector to alter the type instantiated for a particular controller. (Please note I have not tested this to exhaustion)
Update the decorator to be generic
public class MyHttpControllerDecorator<T> : MyHttpController
where T : MyHttpController
{
public readonly T decoratee;
public MyHttpControllerDecorator(T decoratee)
{
this.decoratee = decoratee;
}
public Task<HttpResponseMessage> ExecuteAsync(
HttpControllerContext controllerContext,
CancellationToken cancellationToken)
{
return this.decoratee.ExecuteAsync(controllerContext, cancellationToken);
}
[ActionName("Default")]
public DtoModel Get(int id)
{
return this.decoratee.Get(id);
}
}
Define the custom implementation of IHttpControllerSelector
public class CustomControllerSelector : DefaultHttpControllerSelector
{
private readonly HttpConfiguration configuration;
public CustomControllerSelector(HttpConfiguration configuration)
: base(configuration)
{
this.configuration = configuration;
}
public override HttpControllerDescriptor SelectController(
HttpRequestMessage request)
{
var controllerTypes = this.configuration.Services
.GetHttpControllerTypeResolver().GetControllerTypes(
this.configuration.Services.GetAssembliesResolver());
var matchedTypes = controllerTypes.Where(i =>
typeof(IHttpController).IsAssignableFrom(i)).ToList();
var controllerName = base.GetControllerName(request);
var matchedController = matchedTypes.FirstOrDefault(i =>
i.Name.ToLower() == controllerName.ToLower() + "controller");
if (matchedController.Namespace == "WebApiTest.Controllers")
{
Type decoratorType = typeof(MyHttpControllerDecorator<>);
Type decoratedType = decoratorType.MakeGenericType(matchedController);
return new HttpControllerDescriptor(this.configuration, controllerName, decoratedType);
}
else
{
return new HttpControllerDescriptor(this.configuration, controllerName, matchedController);
}
}
}
When registering the controllers, add in the registration of a decorated version of the controller type
var container = new SimpleInjector.Container();
var services = GlobalConfiguration.Configuration.Services;
var controllerTypes = services.GetHttpControllerTypeResolver()
.GetControllerTypes(services.GetAssembliesResolver());
Type decoratorType = typeof(MyHttpControllerDecorator<>);
foreach (var controllerType in controllerTypes)
{
if (controllerType.Namespace == "WebApiTest.Controllers")
{
Type decoratedType = decoratorType.MakeGenericType(controllerType);
container.Register(decoratedType, () =>
DecoratorBuilder(container.GetInstance(controllerType) as dynamic));
}
else
{
container.Register(controllerType);
}
}
Register the implementation of IHttpControllerSelector
GlobalConfiguration.Configuration.Services.Replace(
typeof(IHttpControllerSelector),
new CustomControllerSelector(GlobalConfiguration.Configuration));
This is the method for creating the Decorated instance
private MyHttpControllerDecorator<T> DecoratorBuilder<T>(T instance)
where T : IHttpController
{
return new MyHttpControllerDecorator<T>(instance);
}

Categories

Resources