Trying to use IPipelineBehavior with ASP.NET Core - get System.InvalidCastException - mediatr

I'm using Mediatr 3's new features for Pipeline Behaviors. Problem is, when I wire them into Mediatr, exceptions (System.InvalidCastException) get thrown for every .Send() call. Handlers get called fine, but when its time for the pipeline behaviors to get called, it fails.
Here's my setup:
services.AddScoped<SingleInstanceFactory>(p => t => p.GetRequiredService(t));
services.AddScoped<MultiInstanceFactory>(p => t => GetRequiredServices(p,t));
services.AddScoped(typeof( IPipelineBehavior<, >), typeof(AddSessionBehavior<, >));
services.AddMediatR();
And my Behavior:
public class AddSessionBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
{
IHttpContextAccessor Accessor;
public AddSessionBehavior(IHttpContextAccessor anAccessor)
{
this.Accessor = anAccessor;
}
public async Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next)
{
var response = await next();
return response;
}
}
When I send my first message through mediator, I get:
System.InvalidCastException occurred
HResult=0x80004002
Message=Object cannot be stored in an array of this type.
Source=<Cannot evaluate the exception source>
StackTrace:
at System.Array.InternalSetValue(Void* target, Object value)
at System.Array.SetValue(Object value, Int32[] indices)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitClosedIEnumerable(ClosedIEnumerableCallSite closedIEnumerableCallSite, ServiceProvider provider)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitTransient(TransientCallSite transientCallSite, ServiceProvider provider)
at Microsoft.Extensions.DependencyInjection.ServiceProvider.<>c__DisplayClass16_0.<RealizeService>b__0(ServiceProvider provider)
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
at MediatR.ServiceCollectionExtensions.GetRequiredServices(IServiceProvider provider, Type serviceType)
at MediatR.Internal.RequestHandlerImpl`2.GetPipeline(TRequest request, RequestHandlerDelegate`1 invokeHandler, MultiInstanceFactory factory)
at MediatR.Internal.RequestHandlerImpl`2.Handle(IRequest`1 request, CancellationToken cancellationToken, SingleInstanceFactory singleFactory, MultiInstanceFactory multiFactory)
at MediatR.Mediator.Send[TResponse](IRequest`1 request, CancellationToken cancellationToken)
at Merlin.Web.Controllers.CourseController.Add(CourseAddVM model)
If I comment out the wiring for my behavior, my handlers get called fine. And the rest of the application seems to work.
What have I done wrong?

I figured it out.
Turns out that somewhere along the way an internal class with the same name as my behavior was created in a different namespace in my application. Probably the result of a "Generate Class definition".
Removing the generated class cleared up the issue.

Related

#ExceptionHandler is Not working when automatic binding fails in REST API

I have two REST API's GET POST
When any Exception is thrown inside the method, Exception handler is working fine.
But if i use malformed REST api uri then it only shows 400 Bad Request without going to Exception Handler.
Eg.
If I hit http://localhost:8080/mypojoInteger/abc, it fails to parse string into Integer and hence I am expecting it to go to ExceptionHandler.
It does not go to Exception Handler, Instead I only see 400 Bad Request.
It works fine and goes to Exception Handler when any Exception is thrown inside the GET/POST method.
For eg: It works fine and goes to Exception Handler if I use 123 in path variable
http://localhost:8085/mypojoInteger/123
And change getData method to
#GetMapping("/mypojoInteger/{sentNumber}")
public void getData(#PathVariable("sentNumber") Integer sentNumber) {
throw new NumberFormatException("Exception");
}
NOTE: Same issue is with POST request also.
GET:
#GetMapping("/mypojoInteger/{sentNumber}")
public void getData(#PathVariable("sentNumber") Integer sentNumber) {
//some code
}
POST:
public void postData(#RequestBody MyPojo myPojo) {
//some code
}
Controller Advice class:
#ControllerAdvice
public class CustomGlobalExceptionHandler extends ResponseEntityExceptionHandler {
#ExceptionHandler(NumberFormatException.class)
protected ResponseEntity<Object> handleEntityNotFound(
NumberFormatException ex) {
// some logic
}
}
How can I handle Exception when it fails to bind String to Integer in REST API uri itself??
EDIT: My Requirement is I should handle the overflow value of integer i.e, If a pass more than maximum value of Integer it must handle it rather than throwing NumberFormatException Stack Trace.
Eg: When i pass over flow value
POJO:
public class MyPojo extends Exception {
private String name;
private Integer myInt;
//getters/setter
}
{
"name":"name",
"myInt":12378977977987879
}
Without #ControllerAdvice it just shows the NumberFormatException StackTrace.
With #ControllerAdvice it just shows 400 bad request with no Response Entity.
I do not want this default stacktrace/400 bad request in case of this scenario
but I want to show my custom message.
The reason that i see is that, because since your request itself is malformed-> the method body never gets executed - hence the exception never occurs because it is only meant to handle the error within the method . It is probably a better design choice for you to form a proper request body rather than allowing it to execute any method so you know the problem before hand.
The issue is because Integer object is not sent as a valid request parameter, example of request: 5 if you send String an exception will be thrown directly. If you want to check if it is a String or Integer you might change your code by following this way:
#GetMapping("/mypojoInteger/{sentNumber}")
public void getData(#PathVariable("sentNumber") Object sentNumber) {
if (!(data instanceof Integer)) {
throw new NumberFormatException("Exception");
}
}
This should work on your example.
Solution:
I found out that I need to handle Bad Request.
So, I have override
#Override
protected ResponseEntity<Object> handleHttpMessageNotReadable(HttpMessageNotReadableException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
//Handle Bad Request
}

Simple Injector and routeattribute webapi

I have a WebApi 2 Application and I'm using simple injector and all is working ok.
But today I tried to use the [RoutePrefix] and [Route] attributes to resolve my routes on a particular controller and it seems that simple injector is not able to create an instance of my controller.
i'm getting this error
An error occurred when trying to create a controller of type
'NewController'. Make sure that the controller has a parameterless
public constructor. Type
'Public.API.Controllers.NewController' does not have a default
constructor
Stack trace:
at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)
at System.Web.Http.Controllers.HttpControllerDescriptor.CreateController(HttpRequestMessage request)
at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__1.MoveNext()
at System.Linq.Expressions.Expression.New(Type type)
at System.Web.Http.Internal.TypeActivator.Create[TBase](Type instanceType)
at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.GetInstanceOrActivator(HttpRequestMessage request, Type controllerType, Func`1& activator)
at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)
my controller looks like this
[Authorize]
[RoutePrefix("api/New")]
public class NewController : ApiController
{
private IUserService userService;
public NewController(IUserService userService)
{
this.userService = userService;
}
[HttpPost]
[AllowAnonymous]
public async Task<IHttpActionResult> Register(ApiRegisterUserRequestModel model) {
return Content(HttpStatusCode.OK, "reponse");
}
[HttpPost]
[AllowAnonymous]
[Route("ForgotPasswordSendEmail")]
public async Task<IHttpActionResult> ForgotPasswordSendEmail(
[FromBody] ApiForgotPasswordRequestModel model)
{
var response = "cool";
return Content(HttpStatusCode.OK, response);
}
}
If I make a request to the Register action I get a response, but if I make a request to the ForgotPasswordSendEmail action then I get the error I mentioned above.
The simple injector configuration I have is the Basic setup mentioned here
https://simpleinjector.readthedocs.org/en/latest/webapiintegration.html
UPDATE
I'm using OWIN and JWT token authentication, and I have a global.asax and a startup file in my project and both were configured to use webapi.
These were my Startup class and Application_Start
//startup class
public class Startup
{
public void Configuration(IAppBuilder app)
{
SimpleInjectorWebApiInitializer.Initialize();
HttpConfiguration httpConfig = new HttpConfiguration();
ConfigureOAuthTokenGeneration(app);
ConfigureOAuthTokenConsumption(app);
WebApiConfig.Register(httpConfig);
app.UseWebApi(httpConfig);
}
}
//Application_Start
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
GlobalConfiguration.Configure(WebApiConfig.Register);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
SimpleInjector.Configure();
SimpleInjectorWebApiInitializer.Initialize();
}
I removed all of the api configuration from the startup and left if like this
public class Startup
{
public void Configuration(IAppBuilder app)
{
ConfigureOAuthTokenGeneration(app);
ConfigureOAuthTokenConsumption(app);
}
}
and it started to work.
now, why wasn't it working using the [Route] attribute and without it all was fine? it's a mystery to me.
I've been trying to reproduce this issue, but with no success. You typically get the "Make sure that the controller has a parameterless public constructor" error in case the registered IDependencyResolver.GetService returns null and the requested type does not have a default constructor.
If you, as you said, follow Simple Injector's configuration guidance, the SimpleInjectorWebApiDependencyResolver will not return null, but will either return a valid controller instance -or- will throw an expressive exception. The default guidance states that you at least do the following:
container.RegisterWebApiControllers(GlobalConfiguration.Configuration);
container.Verify();
GlobalConfiguration.Configuration.DependencyResolver =
new SimpleInjectorWebApiDependencyResolver(container);
If you use this code, it's very unlikely that you get this "Make sure that the controller has a parameterless public constructor" error. Especially in the situation where the controller can be resolved when called using one action, while it fails to initialize during another.
So please check the following:
You are using the code as shown above.
Are you sure that api/New/Register call actually goes through the NewController. You can set a break point in its constructor and the Register method.
The NewController can actually be resolved correctly when manually calling container.GetInstance<NewController>().

Web Api and where should I contorol Request Header data

In Asp.net Web Api, I want to control, request "access token" key is (which is in request header) valid or not. But I cound't decide where should I implement this kind of control. ActionFilter or controller constructor etc. etc.
How about using a DelegatingHandler? It is part if the Web Api pipeline and executes before Routing and Controller handlers.
A really simple handler for access tokens may look like this. You would implement IsValid as you see fit.
public class ValidateTokenHandler : DelegatingHandler
{
protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var token = request.Headers.Authorization;
if (token == null or !IsValid(token))
{
return new HttpResponseMessage(System.Net.HttpStatusCode.Unauthorized);
}
return await base.SendAsync(request, cancellationToken);
}
}

Request asynchronous processing does not work

I would like to make my controller (Spring MVC) handle request in parallel. I use #Callable below and it does not work, because next request is handled since first one finished (returns view).
#RequestMapping(method = RequestMethod.GET)
public Callable<String> helloWorld(final Model model) throws InterruptedException {
return new Callable<String>() {
#Override
public String call() throws Exception {
Thread.sleep(5000);
return "helloWorld";
}
};
}
Do I need any special code?
The documentation for Spring MVC states the following about the Callable<?> return type for handler methods
A Callable can be returned when the application wants to produce
the return value asynchronously in a thread managed by Spring MVC.
Spring will take the returned Callable instance, pass it to an ExecutorService (actually does more processing then than that, but for simplicity) and execute it in a different Thread then your initial request. After waiting 5 seconds, it will return the view associated with the view name "helloWorld".

webapi batching and delegating handlers

based on my last post I was able to get batching working... until a certain point. In addition to registering the route specific handler I also have 2 delegating handlers
Authenticate the user
logging
the batch handler goes through the delegating handlers authenticating the user and logging the request. when the messagehandlerinvoker starts to send the child/nested requests the following exception is thrown.
System.ArgumentException was unhandled by user code
HResult=-2147024809
Message=The 'DelegatingHandler' list is invalid because the property 'InnerHandler' of 'AuthenticationMessageHandler' is not null.
Parameter name: handlers
Source=System.Net.Http.Formatting
ParamName=handlers
StackTrace:
at System.Net.Http.HttpClientFactory.CreatePipeline(HttpMessageHandler innerHandler, IEnumerable`1 handlers)
at System.Web.Http.HttpServer.Initialize()
at System.Web.Http.HttpServer.<EnsureInitialized>b__3()
at System.Threading.LazyInitializer.EnsureInitializedCore[T](T& target, Boolean& initialized, Object& syncLock, Func`1 valueFactory)
at System.Threading.LazyInitializer.EnsureInitialized[T](T& target, Boolean& initialized, Object& syncLock, Func`1 valueFactory)
at System.Web.Http.HttpServer.EnsureInitialized()
at System.Web.Http.HttpServer.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
at System.Net.Http.HttpMessageInvoker.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
at RoutingRequest.Service.Startup.BatchMessageHandler.<>c__DisplayClassd.<PrcoessRequest>b__b(Task`1 m) in C:\CEI\Clients\Footlocker.com\FL - Vendor Routing Portal\source\RoutingRequest.Service\Startup\BatchMessageHandler.cs:line 45
at System.Threading.Tasks.ContinuationResultTaskFromResultTask`2.InnerInvoke()
at System.Threading.Tasks.Task.Execute()
InnerException:
is there a config option I am missing, or do I need to bypass the delegating handlers?
edit
here is my authentication handler.
public class AuthenticationMessageHandler
: DelegatingHandler
{
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
SetCurrentUser(request);
return base.SendAsync(request, cancellationToken);
}
private void SetCurrentUser(HttpRequestMessage request)
{
var values = new List<string>().AsEnumerable();
if (request.Headers.TryGetValues("routingrequest-username", out values) == false) return;
var username = values.First();
var user = Membership.GetUser(username, true);
if (user == null)
{
var message = string.Format("membership information for '{0}' could not be found.", username);
throw new HttpRequestException(message);
}
var roles = Roles.GetRolesForUser(username);
Thread.CurrentPrincipal = new GenericPrincipal(new GenericIdentity(user.UserName), roles);
}
}
based on Kiran's answer a subclassed httpserver fixes one issue and introduces another. My roles provider is getting a null reference exception. looking into that now.
That blog post correctly identifies the problem, but there is a simpler solution if you are configuring OWIN using a Startup or OwinStartup class:
Change the OWIN configuration call from
UseWebApi(this IAppBuilder builder, HttpConfiguration configuration);
to
UseWebApi(this IAppBuilder builder, HttpServer httpServer);
so that your batch handler and the OWIN pipeline are using the same HttpServer instance.
The root cause of this is that many of the batching articles/examples (eg http://bradwilson.typepad.com/blog/2012/06/batching-handler-for-web-api.html ) create a new HttpServer for batching in addition to the main HttpServer that is handling HTTP requests; and both HttpServers are using the same HttpConfiguration.
When each HttpServer is initialized the first time it receives requests, it creates a pipeline of handlers (in HttpClientFactory.CreatePipeline) by reversing all the configured delegating handlers (eg tracing handlers, or other proxy-type handlers), and terminating the pipeline with the Web API dispatcher.
If you don't have any delegating handlers configured, then this problem won't bite you - you can have 2 HttpServer objects that use the same HttpConfiguration.
But if you have any delegating handlers explicitly or implicitly configured (eg by enabling Web API Tracing), then Web API can't build the 2nd pipeline - the delegating handlers are already linked in the first pipeline - and this exception is thrown on the first request to the 2nd HttpServer.
This exception should absolutely be more clear about what is going on. Better yet, this problem shouldn't even be possible - configuration should be configuration, not individual handlers. The configuration could be a factory for delegating handlers. But I digress...
While the issue is kinda hard to figure out, there's a pretty easy fix:
If you're using OWIN, pass the same HttpServer as you use in the batch handler to the OWIN pipeline via UseWebApi(this IAppBuilder builder, HttpServer httpServer);
If you're using IIS + Web API (no OWIN Startup class), pass GlobalConfiguration.DefaultServer to your batch handler, to avoid creating a new HttpServer
Here's an example OWIN startup class that creates a single HttpServer and passes it to both the batch handler, and Web API. This example uses to OData batch handler:
[assembly: OwinStartup(typeof(My.Web.OwinStartup))]
namespace My.Web
{
/// <summary>
/// OWIN webapp configuration.
/// </summary>
public sealed class OwinStartup
{
/// <summary>
/// Configure all the OWIN modules that participate in each request.
/// </summary>
/// <param name="app">The OWIN appBuilder</param>
public void Configuration(IAppBuilder app)
{
HttpConfiguration webApiConfig = new HttpConfiguration();
webApiConfig.MapHttpAttributeRoutes();
HttpServer webApiServer = new HttpServer(webApiConfig);
// Configure batch handler
var batchHandler = new DefaultODataBatchHandler(webApiServer);
webApiConfig.Routes.MapODataServiceRoute("ODataRoute",
"odata",
BuildEdmModel(),
new DefaultODataPathHandler(),
ODataRoutingConventions.CreateDefault(),
batchHandler);
app.UseWebApi(webApiServer);
}
private EdmModel BuildEdmModel()
{
// ...
}
}
}
I've had this error without batching. I made an HttpClientFactory of my own and it takes in a HandlerFactory, also my own.
It calls the HandlerFactory.Create() method in the constructor and stores the resulting handlers that it made.
These are passed to the System.Net.Http.HttpClientFactory.Create(...) method whenever the factory needs to make a new HttpClient.
But it's then only good for a single call because the handlers themselves are mutated by the .NET code leaving them in a state that means they cannot be reused.
I altered my constructor so that it doesn't create the handlers up front, but each time. It now works.

Resources