Docker Part 1 - IP Based Inter Container Communication for ASP.NET Core WEB API REST Services 🤟

Here we deploy 2 asp.net core web api applications, named serviceone & servicetwo, inside 2 different local docker containers. Then serviceone will call sericetwo to get it's data.

Tools and Environments Needed

  1. Visual Studio 2019
  2.  Local Docker 
Please ref. this article, asp.net core web api in docker ,  to know how to create asp.net core web api applications running in docker locally. Here we create 2 asp.net core webapi services i.e. serviceone & servicetwo. You make sure that your local docker service is running.
 

 
 
 

Configure Target Service (servicetwo)

Service with a name servicetwo is providing data. So we can call it a target service. 
Below code showing the exposed API(Weather) of servicetwo, which is returning an Array of type WeatherForecast. Please refer the uploaded project to see this code.
  1. [ApiController]  
  2.    [Route("api/[controller]/[action]")]  
  3.    public class WeatherForecastController : ControllerBase  
  4.    {  
  5.        private static readonly string[] Summaries = new[]  
  6.        {  
  7.            "Freezing""Bracing""Chilly""Cool""Mild""Warm""Balmy""Hot""Sweltering""Scorching"  
  8.        };  
  9.   
  10.        private readonly ILogger<WeatherForecastController> _logger;  
  11.   
  12.        public WeatherForecastController(ILogger<WeatherForecastController> logger)  
  13.        {  
  14.            _logger = logger;  
  15.        }  
  16.   
  17.        [HttpGet]  
  18.        public IEnumerable<WeatherForecast> Weather()  
  19.        {  
  20.            var rng = new Random();  
  21.            return Enumerable.Range(1, 5).Select(index => new WeatherForecast  
  22.            {  
  23.                Date = DateTime.Now.AddDays(index),  
  24.                TemperatureC = rng.Next(-20, 55),  
  25.                Summary = Summaries[rng.Next(Summaries.Length)]  
  26.            })  
  27.            .ToArray();  
  28.        }  
  29.    } 
 
Now run this servicetwo selecting docker as host locally.
 
 
 
Please confirm the output like below. Please understand that this web page has been launched from a docker container and so this local service (servicetwo) with its' API has been hosted in a local docker container. You need to find that container IP for any communication with this specific API. You can't use the browser address displaying here for internal service communication, if using containers.
 
 
 

Now servicetwo is running and you need to find the IP address of the container under which servicetwo is running. You can't use the URL displayed in above browser for internal service communication, if using containers. Run below docker commands to get the container IP.
  •  Run "docker ps" to see all local docker containers running and from there identify "servicetwo" container to get it's container id. You might noticed that,  "8991ea0996fd" is the container id of servicetwo.
  •  Run "docker inspect -f "{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}" 8991ea0996fd" to see the IP of the servicetwo container. Usually "docker inspect" command will return load of information, but we are interested only in IP. That filter has been mentioned with a paramter "-f"

 
 Now our target service, servicetwo, is running and we know it's container IP as well. Time to write code for source service i.e. serviceone, to communicate and pull data from servicetwo
 
 

Configure SourceService (serviceone)

 
Service with a name serviceone is pulling data from servicetwo.
Below code showing the API is calliing a method CallServiceTwo(), which internally calling target service i.e. servicetwo. The line "BaseAddress = new Uri("http://172.17.0.3/api/")" is the key, where we used the container IP of the servicetwo for the communication. Remaining code sections all as like a normal HttpClient call. Please refer the uploaded project to see this code.
 
  1. [ApiController]  
  2.    [Route("[controller]")]  
  3.    public class WeatherForecastController : ControllerBase  
  4.    {  
  5.   
  6.        private readonly ILogger<WeatherForecastController> _logger;  
  7.   
  8.        public WeatherForecastController(ILogger<WeatherForecastController> logger)  
  9.        {  
  10.            _logger = logger;  
  11.        }  
  12.   
  13.        [HttpGet]  
  14.        public IEnumerable<WeatherForecast> Get()  
  15.        {  
  16.            return CallServiceTwo().ToArray();  
  17.        }  
  18.        private static IEnumerable<WeatherForecast> CallServiceTwo()  
  19.        {  
  20.            IEnumerable<WeatherForecast> weatherData = new List<WeatherForecast>();  
  21.            try  
  22.            {  
  23.                using var client = new HttpClient  
  24.                {  
  25.                    BaseAddress = new Uri("http://172.17.0.3/api/")  
  26.                };  
  27.   
  28.                client.DefaultRequestHeaders.Accept.Clear();  
  29.                client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));  
  30.                var response = client.GetAsync("weatherforecast/weather").Result;  
  31.                if (response.IsSuccessStatusCode)  
  32.                {  
  33.                    var jsonTask = response.Content.ReadAsAsync<IEnumerable<WeatherForecast>>();  
  34.                    jsonTask.Wait();  
  35.                    weatherData = jsonTask.Result; ;  
  36.   
  37.                }  
  38.   
  39.            }  
  40.            catch (Exception ex)  
  41.            {  
  42.                Console.WriteLine(ex.Message);  
  43.            }  
  44.            return weatherData;  
  45.        }  
  46.    } 
 
Now you run serviceone and see below debug point to understand the runtime execution and values returning from servicetwo.
 
 
 
Last, confirm serviceone UI also as like below.
 
 
Here overall idea is to understand the basic container level communication using IP, if you deploy services across different containers. This is a practical scenario if you are deploying Microservices in an Azure Kubernetes Service host. In real world, using IP to communicate across containers may not be a proper choice and we need specific DNS to identify them. I will explain that approach in another article.