Request.IsLocal in ASP.NET Core

· 536 words · 3 minutes to read

In the “classic” ASP.NET, System.Web.HttpRequest gave us a fairly useful IsLocal property which developers used to identify local requests.

It returned true if the IP address of the request originator was 127.0.0.1 or if the IP address of the request was the same as the server’s IP address.

ASP.NET Core RC1 exposed similar type of information on its ConnectionInfo object (hanging off HttpContext) and via an IHttpConnectionFeature. However, this is being removed in RC2.

Let’s see how you can quickly add it back as extension method, so that you can use it going forward.

Adding Request.IsLocal in ASP.NET Core 🔗

Before we begin, a quick reminder that if you have been working with ASP.NET in recent years, it’s possible this is not the first time you are adding this type of functionality.

ASP.NET Web API had no dependency on System.Web.dll, and it’s HTTP object model - HttpRequestMessage to be precise - didn’t expose such information either. The framework however did keep track of the locality of the request based on the information set by the host, and it could be extracted from there.

In a similar fashion, in ASP.NET Core, the host (server) will keep track of the key connection information and expose that through the IHttpConnectionFeature. Based on that, we can identify whether we are dealing with a local HTTP request.

A simple extension method for Microsoft.AspNetCore.Http.HttpRequest is shown below.

public static class HttpRequestExtensions  
{  
public static bool IsLocal(this HttpRequest req)  
{  
var connection = req.HttpContext.Connection;  
if (connection.RemoteIpAddress != null)  
{  
if (connection.LocalIpAddress != null)  
{  
return connection.RemoteIpAddress.Equals(connection.LocalIpAddress);  
}  
else  
{  
return IPAddress.IsLoopback(connection.RemoteIpAddress);  
}  
}

// for in memory TestServer or when dealing with default connection info  
if (connection.RemoteIpAddress == null && connection.LocalIpAddress == null)  
{  
return true;  
}

return false;  
}  
}  

The Connection property hanging off HttpContext is - by default - just a shortcut to IHttpConnectionFeature populated by the the underlying host.

To determine whether request is local, we can check if the RemoteIpAddress and LocalIpAddress on the connection are the same, or, in case the local IP is unknown for some reason, if the RemoteIpAddress is a loopback address.

What’s important to note here is that this connection information (as well as all other info in the ASP.NET Core feature interfaces like IHttpConnectionFeature) is set per request - in this case by the server middleware.

For example if you are running on IIS, it will be the IIS integration middleware. A by-product of this is that if you try to use this technique in any middleware registered earlier than the IIS middleware, the connection information will be incorrect (or rather, just empty defaults).

Finally, when you run behind a reverse proxy of some sort (even on Azure website), the RemoteIpAddress reported by Kestrel will be the IP of the proxy. However, if you use IIS middleware, it will know how to understand the X-Forwarded and related headers to correctly receive the IP from the proxy and the connection information will be exposed correctly to your code.

On the other hand, if you don’t use the IIS integration, then you will have to handle the proxy headers yourself. There is already an official ForwardedHeadersMiddleware for that (same as IIS integration package would register).

About


Hi! I'm Filip W., a cloud architect from Zürich 🇨🇭. I like Toronto Maple Leafs 🇨🇦, Rancid and quantum computing. Oh, and I love the Lowlands 🏴󠁧󠁢󠁳󠁣󠁴󠁿.

You can find me on Github and on Mastodon.

My Introduction to Quantum Computing with Q# and QDK book
Microsoft MVP