1

I am not having issue getting user IP address while the code is running in web API controller but in model I am actually unable to use:

this.HttpContext.Connection.RemoteIpAddress.MapToIPv4().ToString();

The reason I need need user IP because I need to geolocate its country by comparing it via data available from a third party provider. I could do this during web API controller phase but it is better to have in model, this way I can create a custom annotation to do my job as I will need to reuse the code in several models.

Suleman
  • 644
  • 3
  • 12
  • 23

2 Answers2

4

You're breaking SOLID here. It's not appropriate for you model to know about HttpContext or how to retrieve a remote IP address from that. The logic you want to encapsulate in your model simply needs an IP address, so that is what you should give it. This can either be provided in the constructor of your model class or just as a param to the particular method(s) that need to utilize it. For example, create a method like:

public void GeolocateByIP(string ip)
{
    // do geolocation
}

In your controller action, then, you simply do something like:

model.GeolocateByIP(HttpContext.Connection.RemoteIpAddress.MapToIPv4().ToString());
Chris Pratt
  • 232,153
  • 36
  • 385
  • 444
  • This actually makes sense, I was wondering why I was getting null IHttpContextAccessor in the constructor of my model. – Suleman Oct 08 '18 at 14:10
  • The `HttpContextAccessor` service is not registered by default, as there's a slight performance hit, and ASP.NET Core is religious about only including what is absolutely necessary in your pipeline. It can be added, if you need it, via `services.AddHttpContextAccessor()`. However, here you should still just pass the IP address string instead. – Chris Pratt Oct 08 '18 at 14:12
  • But I already added it as singleton, I have this line of code in my startup.cs services.AddSingleton(); – Suleman Oct 08 '18 at 14:13
  • First, you should *not* have that line at all. Second, that has nothing to do with `HttpContext`. – Chris Pratt Oct 08 '18 at 14:15
  • I added services.AddHttpContextAccessor() but debugger still shows it is null in constructor when I call it – Suleman Oct 08 '18 at 14:20
  • 1
    1) Your model class must be instantiated by the service collection, or the dependency will not be satisfied. In other words, if you do something like `new MyModel()` or your model instance is coming as an action param, for instance, that will not work. 2) The `HttpContext` is only available during the context of a request. If you're using this class outside of a controller action, for example, there's a high likelihood it would be null regardless. – Chris Pratt Oct 08 '18 at 14:23
  • Yes I was using it in the model class itself (outside the controller), this is why I see it is Null. – Suleman Oct 08 '18 at 14:26
0

You can access HttpContext by injecting IHttpContextAccesor in asp.net core.

public class ModelClass
{
    private readonly IHttpContextAccessor _httpContextAccessor;

    public ModelClass(IHttpContextAccessor httpContextAccessor)
    {
        _httpContextAccessor = httpContextAccessor;
    }
}
Tech Yogesh
  • 427
  • 4
  • 18