This is a backport to ASP.NET Core 2.1 (and 2.2) of the HeaderPropagation middleware I had recently contributed to the ASP.NET Core project. All code is licensed under the Apache License, Version 2.0 and copyrighted by the .NET Foundation.
If you are using ASP.NET Core 3.0, please use the official package Microsoft.AspNetCore.HeaderPropagation.
I believe it is a common use case which deserves to be included in ASP.NET Core. Its main use case is probably to track distributed transaction which requires the ability to pass through a transaction identifier as well as generating a new one when not present.
Given the ASP.NET Core 3.0 release is quite far away, and the current policy doesn't allow to backport new features to already shipped releases, I have created this package as recommended so it can be used today on projects based on ASP.NET Core 2.1 or 2.2.
In Startup.Configure
enable the middleware:
app.UseHeaderPropagation();
In Startup.ConfigureServices
add the required services, eventually specifying a configuration action:
services.AddHeaderPropagation(o =>
{
// propagate the header if present
o.Headers.Add("User-Agent");
// if still missing, set it with a value factory
o.Headers.Add("User-Agent", context => "Mozilla/5.0 (trust me, I'm really Mozilla!)");
// propagate the header if present, using a different name in the outbound request
o.Headers.Add("Accept-Language", "Lang");
});
If you are using the HttpClientFactory
, add the DelegatingHandler
to the client configuration using the AddHeaderPropagation
extension method.
services.AddHttpClient<GitHubClient>(c =>
{
c.BaseAddress = new Uri("https://api.github.com/");
c.DefaultRequestHeaders.Add("Accept", "application/vnd.github.v3+json");
}).AddHeaderPropagation();
Or propagate only a specific header, also redefining the name to use
services.AddHttpClient("example", c =>
{
c.BaseAddress = new Uri("https://api.github.com/");
c.DefaultRequestHeaders.Add("Accept", "application/vnd.github.v3+json");
}).AddHeaderPropagation(o =>
{
o.Headers.Add("User-Agent", "Source");
});
HeaderPropagationOptions
contains a dictionary where the key represent the name of the header to consume from the incoming request.
Each entry define the behaviour to propagate that header as follows:
InboundHeaderName
is the name of the header to be captured.CapturedHeaderName
determines the name of the header to be used by default for the outbound http requests. If not specified, defaults toInboundHeaderName
.- When present, the
ValueFilter
delegate will be evaluated once per request to provide the transformed header value. The delegate will be called regardless of whether a header with the name corresponding toInboundHeaderName
is present in the request. It should returnStringValues.Empty
to not add the header. - If multiple configurations for the same header are present, the first which returns a value wins.
Please note the factory is called only once per incoming request and the same value will be used by all the outbound calls.
HeaderPropagationMessageHandlerOptions
allows to customize the behaviour per clients, where each entry define the behaviour as follows:
CapturedHeaderName
is the name of the header to be used to lookup the headers captured.OutboundHeaderName
is the name of the header to be added to the outgoing http requests. If not specified, defaults toCapturedHeaderName
.
This feature would not have been possible without the help of @rynowak who helped to refine it and get it merged into ASP.NET Core.
You can find the list of contributions in the original repository.