

Properly Propagating "azds-route-as" in Azure Dev Spaces
source link: https://blogs.u2u.be/lander/post/2019/09/16/properly-propagating-azds-route-as-in-azure-dev-spaces
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Routing in Azure Dev Spaces
Azure Dev Spaces is pure dopamine, it makes debugging and integreation testing a breeze in a complex kubernetes setup. And the best thing is: you don't need to modify anything in your code to make it work.
Except for one thing...
To make routing work properly, you need to forward the "azds-route-as" header when making outgoing HTTP calls. That means you have to write code like this for EVERY SINGLE CALL:
var request = new HttpRequestMessage();
request.RequestUri = new Uri("http://mywebapi/api/values/1");
if (this.Request.Headers.ContainsKey("azds-route-as"))
{
// Propagate the dev space routing header
request.Headers.Add("azds-route-as", this.Request.Headers["azds-route-as"] as IEnumerable<string>);
}
var response = await client.SendAsync(request);
(this is a snippet of the official tutorial)
Unacceptable! To hide this monstrosity, I'll make use of a DelegatingHandler
to intercept outgoing HTTP messages and add the "azds-route-as" header on-the-fly.
Talking to the Backend
I made a separate class for all communication with my backend. As a good boy, I used the HttpClientFactory with dependency injection.
BackHttpClient.cs
public class BackHttpClient : IBackHttpClient
{
private readonly HttpClient client;
public BackHttpClient(HttpClient client)
{
this.client = client;
}
public async Task<string> GetValueAsync(int id)
{
var response = await client.GetAsync($"api/values/{id}");
if (response.IsSuccessStatusCode)
{
var result = await response.Content.ReadAsStringAsync();
return result;
}
else
{
throw new Exception($"Value with id {id} could not be retrieved: {response.ReasonPhrase}");
}
}
}
Startup.cs
services.AddHttpClient<IBackHttpClient, BackHttpClient>(client =>
{
client.BaseAddress = new Uri("http://localhost:63448");
client.DefaultRequestHeaders.Add("Accept", "application/json");
})
(I used a local service, so you don't have to set up an AKS to run the demo)
Intercepting the Message
Since I don't want to worry about the "azds-route-as" header with every http call, I'm going to intercept every call before it is made.
ASP.NET Core middleware is not going to be of any help here. This middleware is used for incoming HTTP calls, not outgoing. Instead you can add a collection of DelegatingHandler
objects to your HttpClient
. This builds an outgoing pipeline for the HttpClient
similar to the ASP.NET Core middleware.

The following DelegatingHandler
will add the "azds-route-as" header to the outgoing request if it was set on the incoming request. Notice that getting the incoming request is not straightforward and will be done in the next part.
RoutingHttpHandler
public class RoutingHttpHandler : DelegatingHandler
{
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage outgoingRequest, CancellationToken cancellationToken)
{
//var incomingRequest = ???; //TODO
// Propagate the dev space routing header
if (incomingRequest.Headers.ContainsKey("azds-route-as"))
{
outgoingRequest.Headers.Add("azds-route-as", incomingRequest.Headers["azds-route-as"] as IEnumerable<string>);
}
return base.SendAsync(outgoingRequest, cancellationToken);
}
}
By using AddHttpMessageHandler
, I can add the DelegatingHandler
to the HttpClient
injected into my IBackHttpClient
.
Startup.cs
services.AddTransient<RoutingHttpHandler>();
services.AddHttpClient<IBackHttpClient, BackHttpClient>(client =>
{
client.BaseAddress = new Uri("http://localhost:63448");
client.DefaultRequestHeaders.Add("Accept", "application/json");
})
.AddHttpMessageHandler<RoutingHttpHandler>();
Getting the HttpContext
The final piece of the puzzle is getting the incoming HTTP Request. Since HttpContext.Current
is not available in .NET Core, I will need another trick: the IHttpContextAccessor
. This is basically the injectable version of HttpContext.Current
, and is the result of Microsoft's continuing effort to replace static singletons with injectable ones.
Startup.cs
services.AddHttpContextAccessor();
services.AddTransient<RoutingHttpHandler>();
services.AddHttpClient<IBackHttpClient, BackHttpClient>(client =>
{
client.BaseAddress = new Uri("http://localhost:63448");
client.DefaultRequestHeaders.Add("Accept", "application/json");
})
.AddHttpMessageHandler<RoutingHttpHandler>();
RoutingHttpHandler.cs
public class RoutingHttpHandler : DelegatingHandler
{
private readonly IHttpContextAccessor httpContextAccessor;
public RoutingHttpHandler(IHttpContextAccessor httpContextAccessor)
{
this.httpContextAccessor = httpContextAccessor;
}
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage outgoingRequest, CancellationToken cancellationToken)
{
var incomingRequest = httpContextAccessor.HttpContext.Request;
// Propagate the dev space routing header
if (incomingRequest.Headers.ContainsKey("azds-route-as"))
{
outgoingRequest.Headers.Add("azds-route-as", incomingRequest.Headers["azds-route-as"] as IEnumerable<string>);
}
return base.SendAsync(outgoingRequest, cancellationToken);
}
}
Conclusion
With a little bit of effort, you can shield your code from the requirements to use Azure Dev Spaces, resulting in a more flexible, futureproof application.
You can find all the code here.
Recommend
-
77
The one true way to draw sprites fast. Ever wanted WebGL / OpenGL to draw a quad given only a single point and size? Set color, rotation and texture per sprite, not per vertex? Like this (click for fireworks):
-
47
Properly Deploy Your React App to Heroku Are you using thedevelopmentbuild inproduction? Let’s fix that! Why it’s important to use the production build (
-
74
In this example we will learn how to properly connect to Mysql database using mysqli.
-
64
README.md RichTextView
-
13
Propagating a DNS change … Slowly 4 months ago I’ve bought a couple of .com domains recently from
-
15
Out with the Old, Bring in the New Alas! Azure Dev Spaces has fallen! But we welcome its successor:
-
10
New issue Enable propagating host rustflags to build scripts #10395 Merged ...
-
8
Connecting Azure Express Route with Multiple Virtual Networks Unlike a traditional hub and spoke when you have site to site VPN with azure with multiple virtual networks. Azure Express route gives you an additiona...
-
1
How to wait for multiple C++ coroutines to complete before propagating failure, initial plunge
-
4
The5threich's blog Rating pred...
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK