326

Can you please let me know how to get client IP address in ASP.NET when using MVC 6. Request.ServerVariables["REMOTE_ADDR"] does not work.

abatishchev
  • 95,331
  • 80
  • 293
  • 426
eadam
  • 19,581
  • 15
  • 44
  • 71

22 Answers22

417

The API has been updated. Not sure when it changed but according to Damien Edwards in late December, you can now do this:

var remoteIpAddress = request.HttpContext.Connection.RemoteIpAddress;
David Peden
  • 16,530
  • 6
  • 48
  • 70
147

In project.json add a dependency to:

"Microsoft.AspNetCore.HttpOverrides": "2.2.0"

In Startup.cs, in the Configure() method add:

app.UseForwardedHeaders(new ForwardedHeadersOptions
{
    ForwardedHeaders = ForwardedHeaders.XForwardedFor |
    ForwardedHeaders.XForwardedProto
});  

And, of course:

using Microsoft.AspNetCore.HttpOverrides;

Then, I could get the ip by using:

Request.HttpContext.Connection.RemoteIpAddress

In my case, when debugging in VS I got always IpV6 localhost, but when deployed on an IIS I got always the remote IP.

Some useful links: How do I get client IP address in ASP.NET CORE? and RemoteIpAddress is always null

The ::1 is maybe because of:

Connections termination at IIS, which then forwards to Kestrel, the v.next web server, so connections to the web server are indeed from localhost. (https://stackoverflow.com/a/35442401/5326387)

Edit 12/2020: Thanks to SolidSnake: as of Dec 2020 the latest version is 2.2.0

Edit 06/2021: Thanks to Hakan Fıstık: In .NET 5 the namespace is Microsoft.AspNetCore.Builder

Johna
  • 2,091
  • 1
  • 20
  • 33
  • 14
    This is the correct answer, that is also documented on the official documentation about reverse proxies: https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/linux-nginx?tabs=aspnetcore2x#why-use-a-reverse-proxy-server – Melvyn Feb 27 '18 at 20:38
  • 30
    need to point out that the "app.UseForwardedHeaders..." needs to be added before the app.UseAuthentication(); line, in case you use indentity – netfed Apr 06 '18 at 01:09
  • 3
    This worked perfectly and I have tested is on locally hosted IIS and on Azure. Works both places. – ThomasCle Apr 27 '18 at 11:30
  • 3
    as of Dec 2020 the latest version is 2.2.0 – Desolator Dec 14 '20 at 21:24
  • 3
    In .NET 5 the namespace is `Microsoft.AspNetCore.Builder` – Hakan Fıstık Jun 09 '21 at 18:53
  • 2
    @HakanFıstık Nothing changed, the `UseForwardedHeaders()` extension method and the `ForwardedHeadersOptions` class was always in `Microsoft.AspNetCore.Builder` while `ForwardedHeaders` is still in `Microsoft.AspNetCore.HttpOverrides` – yoel halb Aug 02 '21 at 23:11
102

Some fallback logic can be added to handle the presence of a Load Balancer.

Also, through inspection, the X-Forwarded-For header happens to be set anyway even without a Load Balancer (possibly because of additional Kestrel layer?):

public string GetRequestIP(bool tryUseXForwardHeader = true)
{
    string ip = null;

    // todo support new "Forwarded" header (2014) https://en.wikipedia.org/wiki/X-Forwarded-For

    // X-Forwarded-For (csv list):  Using the First entry in the list seems to work
    // for 99% of cases however it has been suggested that a better (although tedious)
    // approach might be to read each IP from right to left and use the first public IP.
    // http://stackoverflow.com/a/43554000/538763
    //
    if (tryUseXForwardHeader)
        ip = GetHeaderValueAs<string>("X-Forwarded-For").SplitCsv().FirstOrDefault();

    // RemoteIpAddress is always null in DNX RC1 Update1 (bug).
    if (ip.IsNullOrWhitespace() && _httpContextAccessor.HttpContext?.Connection?.RemoteIpAddress != null)
        ip = _httpContextAccessor.HttpContext.Connection.RemoteIpAddress.ToString();

    if (ip.IsNullOrWhitespace())
        ip = GetHeaderValueAs<string>("REMOTE_ADDR");

    // _httpContextAccessor.HttpContext?.Request?.Host this is the local host.

    if (ip.IsNullOrWhitespace())
        throw new Exception("Unable to determine caller's IP.");

    return ip;
}

public T GetHeaderValueAs<T>(string headerName)
{
    StringValues values;

    if (_httpContextAccessor.HttpContext?.Request?.Headers?.TryGetValue(headerName, out values) ?? false)
    {
        string rawValues = values.ToString();   // writes out as Csv when there are multiple.

        if (!rawValues.IsNullOrWhitespace())
            return (T)Convert.ChangeType(values.ToString(), typeof(T));
    }
    return default(T);
}

public static List<string> SplitCsv(this string csvList, bool nullOrWhitespaceInputReturnsNull = false)
{
    if (string.IsNullOrWhiteSpace(csvList))
        return nullOrWhitespaceInputReturnsNull ? null : new List<string>();

    return csvList
        .TrimEnd(',')
        .Split(',')
        .AsEnumerable<string>()
        .Select(s => s.Trim())
        .ToList();
}

public static bool IsNullOrWhitespace(this string s)
{
    return String.IsNullOrWhiteSpace(s);
}

Assumes _httpContextAccessor was provided through DI.

Greg Gum
  • 29,500
  • 31
  • 143
  • 205
crokusek
  • 4,991
  • 2
  • 42
  • 59
  • 4
    THIS is the right answer. There's not a single way to retrieve the IP address, specially when your app is behind a Nginx, a load balancer or something like that. Thanks! – Feu Oct 02 '16 at 02:54
  • @crokusek...trying to adapt your solution, but VS forcing me to the class encapsulating this code static. Do you have this code in your web app project or in a class library in the solution? – dinotom Apr 05 '18 at 17:07
  • The first 2 methods should be in an instance that provides __httpContextAccessor (or adapt it). The second 2 string methods were pulled from a separate static extensions class. – crokusek Apr 05 '18 at 17:22
  • This is a good solution especially when your app uses Kestrel and is hosted with Nginx on Linux. – Timothy Macharia Aug 17 '19 at 14:58
  • 4
    Terrible answer if badly configured. Someone could fake the IP just by injecting X-Forwarded-For header if someone finds the true server's IP. – Lucca Ferri Jan 11 '20 at 21:39
  • This solution works for me, I have a deployment behind a K8s Ingress, also works great if you debug through Ngrok or other port forwarding solution. Some important points: the IsNullOrWhiteSpace and SplitCsv methods should go in a static class as they are extension methods, the other can be used in the context of a controller as the IHttpContextAccessor is required (can be injected through DI as mentioned). – Carlos Aug 12 '20 at 18:31
21

You can use the IHttpConnectionFeature for getting this information.

var remoteIpAddress = httpContext.GetFeature<IHttpConnectionFeature>()?.RemoteIpAddress;
Kiran
  • 55,421
  • 15
  • 173
  • 154
16

In ASP.NET 2.1, In StartUp.cs Add This Services:

services.AddHttpContextAccessor();
services.TryAddSingleton<IActionContextAccessor, ActionContextAccessor>();

and then do 3 step:

  1. Define a variable in your MVC controller

    private IHttpContextAccessor _accessor;
    
  2. DI into the controller's constructor

    public SomeController(IHttpContextAccessor accessor)
    {
        _accessor = accessor;
    }
    
  3. Retrieve the IP Address

    _accessor.HttpContext.Connection.RemoteIpAddress.ToString()
    

This is how it is done.

Aage
  • 5,489
  • 2
  • 28
  • 54
hojjat.mi
  • 1,168
  • 13
  • 20
  • 2
    This gives me ::1. Asp.Net Core 2.2., on localhost. – Stian Oct 02 '19 at 16:46
  • 1
    `::1` is localhost in IPv6. The IPv4 equivalent of `127.0.0.1` – Andy Jan 13 '20 at 21:28
  • 3
    What a terrible answer - IHttpContextAccessor is designed for injected services. The HttpContext is available as a property on Controller, and should be accessed as such. – slippyr4 Aug 10 '21 at 15:16
15

I found that, some of you found that the IP address you get is :::1 or 0.0.0.1

This is the problem because of you try to get IP from your own machine, and the confusion of C# that try to return IPv6.

So, I implement the answer from @Johna (https://stackoverflow.com/a/41335701/812720) and @David (https://stackoverflow.com/a/8597351/812720), Thanks to them!

and here to solution:

  1. add Microsoft.AspNetCore.HttpOverrides Package in your References (Dependencies/Packages)

  2. add this line in Startup.cs

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        // your current code
    
        // start code to add
        // to get ip address
        app.UseForwardedHeaders(new ForwardedHeadersOptions
        {
        ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
        });
        // end code to add
    
    }
    
  3. to get IPAddress, use this code in any of your Controller.cs

    IPAddress remoteIpAddress = Request.HttpContext.Connection.RemoteIpAddress;
    string result = "";
    if (remoteIpAddress != null)
    {
        // If we got an IPV6 address, then we need to ask the network for the IPV4 address 
        // This usually only happens when the browser is on the same machine as the server.
        if (remoteIpAddress.AddressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6)
        {
            remoteIpAddress = System.Net.Dns.GetHostEntry(remoteIpAddress).AddressList
    .First(x => x.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork);
        }
        result = remoteIpAddress.ToString();
    }
    

and now you can get IPv4 address from remoteIpAddress or result

Sruit A.Suk
  • 6,688
  • 7
  • 59
  • 70
14
var remoteIpAddress = HttpContext.Features.Get<IHttpConnectionFeature>()?.RemoteIpAddress;
feradz
  • 1,255
  • 1
  • 16
  • 28
11

This works for me (DotNetCore 2.1)

[HttpGet]
public string Get() 
{
    var remoteIpAddress = HttpContext.Connection.RemoteIpAddress;
    return remoteIpAddress.ToString();
}
Manoj Choudhari
  • 4,636
  • 2
  • 18
  • 31
MC9000
  • 1,617
  • 7
  • 39
  • 65
5

In my case, I have DotNet Core 2.2 Web App running on DigitalOcean with docker and nginx as reverse proxy. With this code in Startup.cs I can get the client IP

app.UseForwardedHeaders(new ForwardedHeadersOptions
        {
            ForwardedHeaders = ForwardedHeaders.All,
            RequireHeaderSymmetry = false,
            ForwardLimit = null,
            KnownNetworks = { new IPNetwork(IPAddress.Parse("::ffff:172.17.0.1"), 104) }
        });

::ffff:172.17.0.1 was the ip that I was getting before using

Request.HttpContext.Connection.RemoteIpAddress.ToString();
gorums
  • 1,231
  • 12
  • 5
5

As of September 2021 - ASP.NET Core (5.x) MVC project allowed me to get the IP Address this way in my controller:

Request.HttpContext.Connection.RemoteIpAddress

Quite a bit more simple now than in the past, it seems.

raddevus
  • 7,113
  • 5
  • 61
  • 73
4

In .NET 5 I use this to retrieve the client IP via a container on AWS fargate.

public static class HttpContextExtensions
{
    //https://gist.github.com/jjxtra/3b240b31a1ed3ad783a7dcdb6df12c36

    public static IPAddress GetRemoteIPAddress(this HttpContext context, bool allowForwarded = true)
    {
        if (allowForwarded)
        {
            string header = (context.Request.Headers["CF-Connecting-IP"].FirstOrDefault() ?? context.Request.Headers["X-Forwarded-For"].FirstOrDefault());
            if (IPAddress.TryParse(header, out IPAddress ip))
            {
                return ip;
            }
        }
        return context.Connection.RemoteIpAddress;
    }
}

You call it like this:

var ipFromExtensionMethod = HttpContext.GetRemoteIPAddress().ToString();

Source

CodingYourLife
  • 5,662
  • 5
  • 46
  • 65
3

Running .NET core (3.1.4) on IIS behind a Load balancer did not work with other suggested solutions.

Manually reading the X-Forwarded-For header does. This code assumes this header contains one IP.

IPAddress ip;
var headers = Request.Headers.ToList();
if (headers.Exists((kvp) => kvp.Key == "X-Forwarded-For"))
{
    // when running behind a load balancer you can expect this header
    var header = headers.First((kvp) => kvp.Key == "X-Forwarded-For").Value.ToString();
    // in case the IP contains a port, remove ':' and everything after
    ip = IPAddress.Parse(header.Remove(header.IndexOf(':')));
}
else
{
    // this will always have a value (running locally in development won't have the header)
    ip = Request.HttpContext.Connection.RemoteIpAddress;
}

Thanks to @JawadAlShaikh and @BozoJoe for pointing out the IP can contain a port and the X-Forwarded-For can contain multiple IPs.

Aage
  • 5,489
  • 2
  • 28
  • 54
  • 2
    I found that `IPAddress.Parse(header)` will throw an error in case it contain port `ip:port` so a check should be made, or quick hack `IPAddress.Parse(header.Remove(header.IndexOf(':')))` – Jawad Al Shaikh Jul 22 '20 at 15:39
  • For reference, IPEndPoint.Parse effectively parses an IP Address and port – Laurent Jan 14 '21 at 20:29
  • 1
    @JawadAlShaikh is correct. The values in X-Forwarded-For can contain `:port` AND strings with mutiple values in them such as `192.168.1.1, 192.168.100.100` – BozoJoe Jun 09 '21 at 22:34
  • This code throws an exception when the header doesn't contain ':'. header.IndexOf(':') returns -1, which string.Remove() does not like. – Frank Hagenson Jul 13 '21 at 12:48
2

First, in .Net Core 1.0 Add using Microsoft.AspNetCore.Http.Features; to the controller Then inside the relevant method:

var ip = HttpContext.Features.Get<IHttpConnectionFeature>()?.RemoteIpAddress?.ToString();

I read several other answers which failed to compile because it was using a lowercase httpContext, leading the VS to add using Microsoft.AspNetCore.Http, instead of the appropriate using, or with HttpContext (compiler is also mislead).

Guy
  • 942
  • 7
  • 19
1

Running ASP.NET Core 2.1 behind a Traefik reverse Proxy on Ubuntu, I need to set its gateway IP in KnownProxies after installing the official Microsoft.AspNetCore.HttpOverrides package

        var forwardedOptions = new ForwardedHeadersOptions {
            ForwardedHeaders = ForwardedHeaders.XForwardedFor,
        };
        forwardedOptions.KnownProxies.Add(IPAddress.Parse("192.168.3.1"));
        app.UseForwardedHeaders(forwardedOptions);

According to the documentation, this is required if the reverse proxy is not running on localhost. The docker-compose.yml of Traefik has assigned a static IP address:

networks:
  my-docker-network:
    ipv4_address: 192.168.3.2

Alternatively, it should be enough to make sure a known network is defined here to specify its gateway in .NET Core.

Lion
  • 14,320
  • 17
  • 71
  • 129
1

As per the official documentation, if you are using Apache or Nginx integration, following code should be added to the Startup.ConfigureServices method.

// using Microsoft.AspNetCore.HttpOverrides;

    services.Configure<ForwardedHeadersOptions>(options =>
    {
        options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | 
            ForwardedHeaders.XForwardedProto;
        // Only loopback proxies are allowed by default.
        // Clear that restriction because forwarders are enabled by explicit 
        // configuration.
        options.KnownNetworks.Clear();
        options.KnownProxies.Clear();
    });

and then on top of everything, in Configure method use

app.UseForwardedHeaders();

Further suppose in nginx conf file, inside a location, use

proxy_set_header   Host $host;
proxy_set_header   X-Real-IP $remote_addr;
proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header   X-Forwarded-Host $server_name;

Now the first entry in the X-Forwarded-For will be the real client IP.

IMPORTANT: If you want to secure the app and not allow an attacker inject X-Forwarded-For, Please read this answer.

Please see Forward the scheme for Linux and non-IIS reverse proxies, Configure Nginx and Dealing with invalid headers

Sayyed Dawood
  • 417
  • 4
  • 14
1

First Add

Microsoft.AspNetCore.Http
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();

in ConfigureServices in Startup.cs Then Add the following code in your controller

   private IHttpContextAccessor _accessor;
    
  public LoginController(IHttpContextAccessor accessor)
            {
              _accessor = accessor;
            }

  public IEnumerable<string> Get()
        {
         var ip = _accessor.HttpContext?.Connection?.RemoteIpAddress?.ToString();
         return new string[] { ip, "value" };
        }

Hope this will work for you

Ali Mumtaz
  • 63
  • 7
1

try this:

string remoteHost = $"{httpContext.Connection.RemoteIpAddress}:{httpContext.Connection.RemotePort}";

lianggan13
  • 21
  • 3
  • 1
    As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Apr 28 '22 at 12:54
0

From this link, there is a better solution.

In Startup.cs, we need to add service-

public void ConfigureServices(IServiceCollection services)
{
    ........
    services.AddHttpContextAccessor();
    ........
}

Then in any controller or any place, we need to use it via dependency injection like this-

private IHttpContextAccessor HttpContextAccessor { get; }

public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options, IWebHostEnvironment env, IHttpContextAccessor httpContextAccessor)
        : base(options)
{
    Environment = env;
    HttpContextAccessor = httpContextAccessor;
    //this.Database.EnsureCreated();
}

And then get IP like this-

IPAddress userIp = HttpContextAccessor.HttpContext.Connection.RemoteIpAddress;
Abrar Jahin
  • 13,156
  • 22
  • 105
  • 151
0

Short version of @crokusek's answer

public string GetUserIP(HttpRequest req)
{
    var ip = req.Headers["X-Forwarded-For"].FirstOrDefault();

    if (!string.IsNullOrWhiteSpace(ip)) ip = ip.Split(',')[0];

    if (string.IsNullOrWhiteSpace(ip)) ip = Convert.ToString(req.HttpContext.Connection.RemoteIpAddress);

    if (string.IsNullOrWhiteSpace(ip)) ip = req.Headers["REMOTE_ADDR"].FirstOrDefault();

    return ip;
}
Mehdi Dehghani
  • 9,600
  • 6
  • 56
  • 58
0
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;

public string GetClientIPAddress(HttpContext context)
    {
        string ip = string.Empty;
if (!string.IsNullOrEmpty(context.Request.Headers["X-Forwarded-For"]))
        {
            ip = context.Request.Headers["X-Forwarded-For"];
        }
        else
        {
            ip = context.Request.HttpContext.Features.Get<IHttpConnectionFeature>().RemoteIpAddress.ToString();
        }
        return ip;
    }

Where you want to get Ip address;

GetClientIPAddress(HttpContext);
-2

To get IP address and hostname in .NET Core, put the following code in the controller:

var addlist = Dns.GetHostEntry(Dns.GetHostName());
string GetHostName = addlist.HostName.ToString();
string GetIPV6 = addlist.AddressList[0].ToString();
string GetIPV4 = addlist.AddressList[1].ToString();
Pang
  • 9,073
  • 146
  • 84
  • 117
-2

try this.

var host = Dns.GetHostEntry(Dns.GetHostName());
        foreach (var ip in host.AddressList)
        {
            if (ip.AddressFamily == AddressFamily.InterNetwork)
            {
                 ipAddress = ip.ToString();
            }
        }
Kunal Burangi
  • 360
  • 4
  • 12