Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Programmatically invoking the ASP.NET Core request pipeline

Tags:

Question

Is there a way to programmatically invoke the ASP.NET Core request pipeline from within my own application, given I have a HTTP verb, the route, headers and body payload?

Background

There are use-cases where the WebAPI of our ASP.NET Core application is not accessible because the application is running behind a firewall or is otherwise not reachable.

To provide a solution for this scenario we want our application to poll some other service for "work-items" which then translate into API calls in our application.

Approaches I considered

  • I could probably just ask DI to give me an instance of a controller and then invoke methods on it. Problems with this approach:
    • Authorization attributes are not enforced. But it is important in our use-case to have the bearer token validated. So here the question would be: How to invoke programmatically the Authorization middleware?
    • I would have to route the incoming work-items to the correct controller/method myself.
  • Using the Microsoft.AspNetCore.TestHost package I could create a TestClient which allows me to make requests to myself (see here). But there are a couple of uncertainties here:
    • The intended use-case of this TestHost is for integration testing. Is it safe to use this in a production environment?
    • Is it even possible to have such a TestServer running alongside the regular hosting?
    • What about thread-safety? Can I create multiple TestClients from a single TestServer instance and use them from different threads?

So I'm sure there must be a cleaner and more direct way to programmatically invoke the request pipeline from within my own application...

like image 340
Robert Hegner Avatar asked May 18 '18 09:05

Robert Hegner


People also ask

How the request pipeline works in ASP.NET Core?

The ASP.NET Core request processing pipeline consists of a sequence of middleware components that are going to be called one after the other. Each middleware component can perform some operations before and after invoking the next component using the next method.

What is the default order of invoking middleware on requests pipeline?

UseRouting , the Routing middleware runs at the beginning of the pipeline by default. For more information, see Routing. The order that middleware components are added in the Program. cs file defines the order in which the middleware components are invoked on requests and the reverse order for the response.

What is ASP Net request pipeline?

The pipeline is the general-purpose framework for server-side HTTP programming that serves as the foundation for ASP.NET pages as well as Web Services. To qualify as a serious ASP.NET developer, you must understand how the pipeline works. This article explains how the HTTP pipeline processes requests.

Which of the following method is used to configure the HTTP pipeline in ASP.NET Core?

Configuring the Request Pipeline This is done in the Configure method of the startup class. The Configure method gets the instance of IApplicationBuilder, using which we can register our Middleware. Or You can create a new ASP.NET Core Application.


1 Answers

Yes, it is actually fairly easy. You can get a reference to the request pipeline at the end of your Startup class Configure method. Save it in a static field / singleton service / etc.

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
  // ... usual configuration code

  AClass.PipelineStaticField = app.Build();
}

Then, in the method you wish to inject the request, you have to build a HttpContext to pass into the pipeline.

var ctx = new DefaultHttpContext();

// setup a DI scope for scoped services in your controllers etc.
using var scope = _provider.CreateScope();
ctx.RequestServices = scope.ServiceProvider;

// prepare the request as needed
ctx.Request.Body = new MemoryStream(...);
ctx.Request.ContentType = "application/json";
ctx.Request.ContentLength = 1234;
ctx.Request.Method = "POST";
ctx.Request.Path = PathString.FromUriComponent("/mycontroller/action");

// you only need this if you are hosting in IIS (.UseIISIntegration())
ctx.Request.Headers["MS-ASPNETCORE-TOKEN"] = Environment.GetEnvironmentVariable("ASPNETCORE_TOKEN");

// setup a place to hold the response body
ctx.Response.Body = new MemoryStream();

// execute the request
await AClass.PipelineStaticField(ctx);

// interpret the result as needed, e.g. parse the body
ctx.Response.Body.Seek(0, SeekOrigin.Begin);
using var reader = new StreamReader(ctx.Response.Body);
string body = await reader.ReadToEndAsync();

That way your request will traverse the whole pipeline including all the middleware such as authentication and authorization.

like image 78
PhillipM Avatar answered Sep 28 '22 17:09

PhillipM