Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

IP Geofencing Engine for .NET

0.00/5 (No votes)
20 Sep 2022 1  
A simple and easily extensible IP geo-fencing engine
This project is about the implementation of a simple and extensible IP geofencing engine. It discusses how geofencing rule are declared, and how to configure, run and extend the geofencing engine.

Overview

Geofencing is the use of virtual geographic perimeters to determine the behavior of an application. Provided a specific coordinate (latitude and longitude), a geofencing engine can determine to which virtual geographic area or areas the location belongs, and consequentially take action.

The IP geofencing engine in this project runs based on specific IP addresses. The engine would first translate the IP address into a geographic location, using the free CSV database provided by IP2Location CSV database (included in the project).

The engine then determines which of the configured geographic areas contain the location, and for each match fires the correspondent configured action. Geographic areas can be configured in the engine by importing a file in GeoJSON format. Sample GeoJSON files are included in this project for testing purposes, and are also freely available for the public on the OpenDataSoft website.

Use Case Scenarios

This engine is particularly useful in cases when the IP address is available, but not the coordinate.
These are the typical scenarios in which web applications can use the engine with the IP address of the http requests:

  • Blocking requests from black-listed geographic areas
  • Enabling/disabling features for specific regions
  • Localizing content
  • Finding the availability of products or service nearby the IP location

Anatomy of a Geofencing Rule

A rule is constructed from three elements: name, predicate and action.

  • rule name: short description for the rule

  • predicate: a boolean function that determines if the rule should be applied. The function will receive as input the list of geographic areas that contain the IP address location (normally only one area if the areas do not overlap), plus the IP address and its location info:

    C#
    predicate: (areas, ip, location) => 
    	{ return areas.Any(A => A.Name == "New York"); }
  • action: a routine that will be executed only if the predicate is evaluated as true. Same inputs as the predicate:
    C#
    action: (areas, ip, location) => 
            { Console.WriteLine($"The IP Address: {ip} is in New York State!"); })

In addition to regular rules, default rules can also be specified. Default rules are executed if and only if the IP address location is not contained in any of the geographic areas available. Unlike regular rules, default rules only need the action to be constructed.

Configuring the Geofencing Engine

C#
var engine = new IPGeoFencingEngineBuilder()
	.AddIP2LocationFromCSVFile(@"\\geofencing\data\IP2LOCATION-LITE-DB11.CSV")
	.AddGeographicAreasFromGeoJSONFile(@"\\geofencing\data\demo.geojson")
	.AddRule("New York", 
		predicate: (areas, ip, location) => 
		{ return areas.Any(A => A.Name == "New York"); },	
		action: (areas, ip, location) => 
		{ Console.WriteLine($"The IP Address: {ip} is in New York State!"); })
	.AddRule("Montana",
		predicate: (areas, ip, location) => 
		{ return areas.Any(A => A.Name == "Montana"); },
		action: (areas, ip, location) => 
		{ Console.WriteLine($"The IP Address: {ip} is in Montana!"); })
	.AddRule("Billings",
		predicate: (areas, ip, location) => 
		{ return areas.Any(A => A.Name == "Billings"); },
		action: (areas, ip, location) => 
		{ Console.WriteLine($"The IP Address: {ip} is in Billings, MT"); })
	.AddRule("Montana but not Billings",
		predicate: (areas, ip, location) => 
		{ return areas.Any(A => A.Name == "Montana") && 
		!areas.Any(A => A.Name == "Billings"); },
		action: (areas, ip, location) => 
		{ Console.WriteLine($"The IP Address: 
          {ip} is in Montana but not in Billings!"); })
	.AddRule("New York or Montana",
		predicate: (areas, ip, location) => 
		{ return areas.Any(A => A.Name == "Montana") || 
		areas.Any(A => A.Name == "New York"); },
		action: (areas, ip, location) => 
		{ Console.WriteLine($"The IP Address: 
          {ip} is in New York State or Montana!"); })
	.AddDefaultAction((ip, loc) => 
	Console.WriteLine($"The IP Address: {ip} is outside all the areas provided"))
	.Build();

Running the Engine

C#
engine.Run("98.127.147.57");   //Billings, MT IP Address
//The IP Address: 98.127.147.57 is in Montana!
//The IP Address: 98.127.147.57 is in Billings, MT
//The IP Address: 98.127.147.57 is in New York State or Montana!

engine.Run("172.254.112.210"); //New York, NY IP Address
//The IP Address: 172.254.112.210 is in New York State!
//The IP Address: 172.254.112.210 is in New York State or Montana!

engine.Run("157.240.3.35");    //Seattle, WA IP Address
//The IP Address: 157.240.3.35 is outside all the areas provided

Running the Demo

The solution comes with a simple demo console app that demonstrates the engine configuration and execution. Before you run the demo, make sure to edit the appsettings.json file included in the project and set the correct full path to the data folder in your file system.

Example:

JavaScript
{
  "DataFolder": "D:\\IPGeoFencing\\Data"
}

Extending the Engine

The core services used by the engine that can be easily extended to enrich its functionality:

IIP2LocationProvider

This interface provides the engine with the translation service to obtain the grographic location from the IP address. The project provides out-of-the-box a simple implementation where the Ip2Location CSV data is loaded entirely in memory and the IP translation occurs via Linq queries. More efficient implementations can be added that utilize databases queries/indexes to look up the locations, or leverage the IP2Location API for a lightweight solution, etc.

C#
public interface IIP2LocationProvider
{
	LocationModel? GetLocationFromIP(IPAddress ipAddress);
	LocationModel? GetLocationFromIP(long ipAddress);
}

IGeographicAreasProvider

This interface is used by the engine to determine which geographic areas contain a given coordinate point. The default implementation in the project is loading in memory the full collection of geographic areas (in the shape of polygons or circles) that need to be evaluated. Like the IIP2LocationProvider, more efficient implementations can be added to leverage databases, particularly those supporting geospatial queries (e.g., MongoDB). Moreover, the project currently only supports the GeoJSON file format to import geographic areas, however there are other popular formats that can be integrated: Shapefile (GIS), KML (Google Earth), etc.

C#
public interface IGeographicAreasProvider
{
	IEnumerable<GeographicAreaModel> GetAreasContaining(GeoCoordinate point);
}

Plugging in Your Own Service Implementations

The engine builder already allows developers to plug in their own service implementations:

C#
IIP2LocationProvider myIP2LocationProvider = 
                     new myOwnIP2LocationProviderImplementation();
IGeographicAreasProvider myGeographicAreasProvider = 
                         new myOwnGeographicAreasProviderImplementation();

var engine = new IPGeoFencingEngineBuilder()
    .AddIP2LocationProvider(myIP2LocationProvider)
    .AddGeographicAreasProvider(myGeographicAreasProvider)
.AddRule( ...

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here