I've been trying to understand how ASP.NET 5 pipeline middlewares really work. A middleware, as I know, is just a Func<RequestDelegate, RequestDelegate>, which is a pointer to a method that receives a reference to the next request delegate and returns a new one that wraps the next. We can of course, use a class to represent a middleware, something like:
public class MyMiddleware
{
private readonly _next;
public MyMiddleware(RequestDelegate next)
{
if (next == null)
{
throw new ArgumentNullException("next");
}
_next = next;
}
public Task Invoke(HttpContext context)
{
// New request delegate code here which can wrap the next one on the pipeline
}
}
Since the RequestDelegate is a delegate that can hold references to methods which receives one HttpContext and returns a Task the Invoke method is the request delegate to be returned and which has access to the next one on the pipeline.
We have then, when coding a middleware, access to the next component of the pipeline, but there is a doubt I have. In the beginning I thought the ideal was always to work the following way:
Check if the middleware can handle the request
If it can, do whatever must be done with the HttpContext
Call the next middleware on the pipeline
So that when I studied this for the first time I thought each middleware should always call the next one. But doing this led to strange behavior as discussed on this question.
Also looking at the source code of some middlewares I see some of them follow another steps:
Check if the middleware can handle the request
If it can, do whatever must be done with the HttpContext and that's all
If not, and only if not call the next one
Is this the real idea of using middlewares? Which way is the correct approach at this? Each middleware do what must be done with the request and always invoke the next or if a midleware can handle the request it doesn't invoke the next anymore?
I believe a middleware should call the next only if it can't handle the request. The reason I think that is because if not, there would be coupling between the middlewares on the pipeline. So that to process the request the middleware would need to be aware of what the previous one did to avoid messing everything. Is this conclusion right?
Middleware exist to make the request pipeline modular, meaning that you can add/remove/replace parts from it as long as you respect the contract. For example, if your application serves some files without any caching, you can add a middleware at the front of the pipeline without altering the rest. They are building blocks.
A middleware can:
Do nothing and pass the request further (e.g. a middleware that is applicable only to POST requests but the current one is GET)
Do nothing to the request, do something else instead and pass it further (e.g. logging)
Do something to the request and pass the request further (e.g. get an authentication token and convert it to an identity, or remove some sensitive information from the request)
End the pipeline and not pass the request further (e.g. StaticFileMiddleware which just returns the file, or MVC when a route matches)
Probably answering your other question too: there are two types of middleware:
Middleware that are designed to do something and pass the data along further (etc. auth, cookies, validation, logging etc)
Middleware that complete the pipeline (static file, MVC, etc).
Of course, some might do both depending on the context. For example auth can end the pipeline if the credentials are incorrect but continue otherwise.
The author of the middleware must decide if the next middleware (if any) should be invoked. In the case of the middleware in your question which returns a message, it should not invoke the next one.
Related
Over the past couple weeks I've been working with an ASP.NET Core Backend(Remote Ubuntu Machine, SSH only, Kestrel).
When sending an HTTP-Request to the Server oftentimes it won't be handled the way I expected it to.
Examples:
For POSTs: An action parameter will be null or 0 or an empty string
the action method isn't executed at all
Is there a way to see the headers, body, etc. of the request that arrived at the Server?
How is the body data processed before the corresponding action method is called?
I've been reading the Console Output and setting breakpoints to figure out whats going on.
Which is fine if there's an Exception thrown or theres something going wrong inside the action method.
But it doesn't help me understand what's happening before the action method is executed.
You can add a middleware in the pipeline to inspect any requests. In the middleware, you will have access to the HttpContext and all its properties (i.e. the request and its headers). As long as you place your app.Use() call before your app.UseMvc() call, you will have access to the request before it enters an action.
More info on middleare is here: https://learn.microsoft.com/en-us/aspnet/core/fundamentals/middleware
Once it enters an action, you have access to the Request object in the controller as well. So you can inspect anything on the request (i.e. headers) however you prefer (locals window, watch window, etc.).
All the properties you can access if you inherit from ControllerBase are here: https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.controllerbase
As Polyfun mentioned, the best approach would be to add robust logging.
We have an asp.net core 2 server.
In performance tests, when we have a few (say tens of) pending requests, new CORS preflight requests stay pending.
It appears that asp.net core has a certain limit on the number of concurrent requests in pipeline, and the default value for that limit is very low.
Is there any resources about these performance related topics?
Is there a way to prioritize requests?
Of course, after we optimize the other requests, this problem will get harder to reproduce, so we want to understand it well enough.
I had answered a similar question related to benchmarking performance for ASP.NET Core Kestrel here.
In short, you could remove the middleware that is causing the bottlenecks, or at least this could help you diagnose the culprit.
Ordering
The order that middleware components are added in the Configure method defines the order in which they are invoked on requests, and the reverse order for the response. This ordering is critical for security, performance, and functionality.
------ Source: Microsoft Docs: ASP.NET Core Middleware
Short-Circuiting
You can short-circuit the request pipeline to handle performance optimizations (or testing) by not calling the next parameter. For example:
public class Startup
{
public void Configure(IApplicationBuilder app)
{
// make sure you place this at the top
// the request pipeline will go in sequence
app.Use(async (context, next) =>
{
// do work for your special case, performance tests, etc
// in order to short-circuit the pipeline, do NOT call the next parameter
// so, you could place some kind of conditional here that will allow only
// specific requests to continue down/up the pipeline
if (!true)
{
await next.Invoke();
}
});
// the rest of the pipeline
}
}
I need to be able to call my SS services from the controllers of an MVC application. Ideally i'd like to call them in-process to avoid the overhead of buiding a http request etc.
From scouring documentation I feel there are 2 suggested methods, but neither work fully.
1) ServiceGateway - Use the service gateway. This calls validation filters, but does not call other customer filters I've added. No option to applyFilters.
2) HostContext.ServiceController.Execute - There is a dedicated option on this method called applyFilters, and when I set it to true it works and applies filters and validation (though it only executes GlobalFilters, not TypedRequestFilters). However, if [CacheResponse] attribute is set on the service it overwrites and flushes a response to my client overriding the flow of the MVC controller and i don't know how to stop this. It does not do this if I set to applyFilters to false or if I take CacheResponse off. Changing the priority of the cache has no effect.
I'm calling the Execute method as follows from within an Action method on my controller:
HostContext.ServiceController.Execute(serviceRequest, HostContext.GetCurrentRequest(), true);
Before this method even returns control a response is flushed to the webpage on Chrome and then nothing/null is returned from method.
I feel there is regarding point 1) a feature missing and point 2) a bug in the implementation, though am not confident enough in my knowledge of SS to remedy either! Please help!
Thanks.
Filters are executed as part of the HTTP Request Pipeline and can terminate the current Request with a custom HTTP Response. You can check IRequest.IsClosed after executing the Request to check if it has been terminated by a Request Filter. They're behavior is incompatible with internal Gateway requests so there's no option to execute them in the Gateway.
I've marked these ServiceController methods as an In Process Request in this commit which should resolve the issue with the [CacheResponse] attribute which ignores In Process Requests.
This change is available from v4.5.13 that's now available on MyGet.
What I am trying to achieve - My application is simply ASP .Net Core application. It is not Web API. I want to execute method before every post/get request from my app to external sources, for example:
I am sending a post request, to check SSL expiry date to some website API and it returns me a response. According to the response I am sending another request or not. I don't want to place call method statement before every request, I would like to do it globally.
I was trying to achieve this based on http://www.sulhome.com/blog/10/log-asp-net-core-request-and-response-using-middleware
As it occurs, this middleware works(I have it working) only for internal requests(routing requests inside application).
Is there any possibility to do it for all requests?
Thanks in advance
.NET Core allows to create custom middlewares to get into MV pipeline. Here is an example:
public class MyMiddleware
{
private readonly RequestDelegate _next;
public MyMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context)
{
//do your checkings
await _next(context);
}
}
In Startup.cs in Config method just regiester it:
app.UseMiddleware<MyMiddleware>(Options.Create(options));
Since you are talking about doing a call on Outgoing requests, you have two mechanisms to solve the problem:
Use an Aspect Oriented Programming Library (like https://www.postsharp.net)
Implement your own Request class (that has the global behavior you desire) and make sure that all requests are done using this class (or a class that inherits from it).
For the second point, a good mechanism is that the base class provides a SendRequest method that receives an HttpRequestMessage and executes the global code. Classes that inherit from it use this method to send the requests and have no access to the underlying HttpClient (so that they cannot run around the SendRequest method).
I am trying to access the Request property in my ApiController-derived class.
For some reason, Request is null in ExecuteAsync method. I've seen the other questions, so before you ask:
I am not initializing the controller by calling the constructor, it's a regular HTTP POST API call from an external device.
I've tried the same request locally with Fiddler, the behavior is identical.
I am not unit testing.
Before hitting the ExecuteAsync method, my request passes through a delegating handler, and in the delegating handler, my request object exists (I even add some properties without any problem).
At the last line of delegating handler, I call return await base.SendAsync(request, cancellationToken); without a problem and request exists.
Right after than in API controller, HttpContext.Current.Request is not null and accessible without problem.
In API controller, RequestContext is not null and accessible without problem.
In that same line, Request is null.
Why would this occur? I'm on Web API 2.2 (and MVC 5, if relevant).
This is probably due to the fact that you're trying to access HttpContext while working with async/await.
So, you have two options:
Access the request via the ExecuteAsync method 'HttpControllerContext' parameter - controllerContext.Request.
Make sure your web.config is targeting .NET 4.5 and update appSettings with aspnet:UseTaskFriendlySynchronizationContext set to true.
You can read more here - Using HttpContext Safely After Async in ASP.NET MVC Applications.
To better understand what's going on under the hood, I'd recommend:
Understand what is SynchronizationContext - ExecutionContext vs SynchronizationContext
Understand how it is related to ASP.NET - Understanding the SynchronizationContext in ASP.NET.
In a very very high level: in a synchronous server implementations, where the entire request is processed by the same thread, the execution context is stored using TLS (thread local storage), means HttpContext is available anywhere in your code.
In an asynchronous server implementation (async/await), the request may be processed by several threads, and there's a need to pass the execution context between those threads.