docker-compose.yml
version: '3.4'
services:
consul:
image: hashicorp/consul:latest
command: consul agent -dev -log-level=warn -ui -client=0.0.0.0
hostname: consul
container_name: consul
networks:
- common_network
ports:
- "8500:8500"
identityservice.httpapi.host:
image: ${DOCKER_REGISTRY-}identityservicehttpapihost
build:
context: .
dockerfile: Services/IdentityService/IdentityService.HttpApi.Host/Dockerfile
environment:
- ASPNETCORE_ENVIRONMENT=Development
- ConnectionStrings__IdentityService=server=DESKTOP;database=IdentityDatabase;Integrated Security=True;TrustServerCertificate=true;
- ConsulConfig__Id=IdentityService-9100
- ConsulConfig__Name=IdentityService
- ConsulConfig__DiscoveryAddress=http://consul:8500
- ConsulConfig__Address=localhost
- ConsulConfig__Port=8000
- ConsulConfig__HealthCheckEndPoint=healthcheck
ports:
- "8000:8080"
networks:
- common_network
depends_on:
- consul
usersettings.httpapi.host:
image: ${DOCKER_REGISTRY-}usersettingshttpapihost
build:
context: .
dockerfile: services/UserSettings/UserSettings.HttpApi.Host/Dockerfile
environment:
- ASPNETCORE_ENVIRONMENT=Development
- ConsulConfig__Id=UserSettingsService-9100
- ConsulConfig__Name=UserSettingsService
- ConsulConfig__DiscoveryAddress=http://consul:8500
- ConsulConfig__Address=localhost
- ConsulConfig__Port=8001
- ConsulConfig__HealthCheckEndPoint=healthcheck
- IdentityService__Address=http://UserSettingsService.openapi:8000
ports:
- "8001:8080"
volumes:
- ${APPDATA}/Microsoft/UserSecrets:/home/app/.microsoft/usersecrets:ro
- ${APPDATA}/ASP.NET/Https:/home/app/.aspnet/https:ro
networks:
- common_network
depends_on:
- consul
networks:
common_network:
driver: bridge
consulhosted.cs
, same for both services
using Consul;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UserSettings.Domain.Models;
namespace UserSettings.Application.Helpers
{
public class ConsulHostedService : IHostedService
{
private readonly IConsulClient _consulClient;
private readonly ConsulConfig _consulConfig;
private readonly IHostApplicationLifetime _lifetime;
private string _registrationId;
private ILogger<ConsulHostedService> _logger;
public ConsulHostedService(IConsulClient consulClient, IOptions<ConsulConfig> consulConfig, ILogger<ConsulHostedService> logger, IHostApplicationLifetime lifetime)
{
_consulClient = consulClient;
_consulConfig = consulConfig.Value;
_lifetime = lifetime;
_logger = logger;
}
public async Task StartAsync(CancellationToken cancellationToken)
{
_registrationId = _consulConfig.Id;
var serviceHost = Environment.GetEnvironmentVariable("HOST_IP") ?? "localhost";
var registration = new AgentServiceRegistration
{
ID = _consulConfig.Id,
Name = _consulConfig.Name,
Address = _consulConfig.Address,
Port = _consulConfig.Port,
};
_logger.LogInformation("Registering service with Consul. ID: {ID}, Name: {Name}, Address: {Address}, Port: {Port}",
registration.ID, registration.Name, registration.Address, registration.Port);
await _consulClient.Agent.ServiceRegister(registration, cancellationToken).ConfigureAwait(false);
_lifetime.ApplicationStopping.Register(async () =>
{
await _consulClient.Agent.ServiceDeregister(_registrationId, cancellationToken);
});
}
public async Task StopAsync(CancellationToken cancellationToken)
{
await _consulClient.Agent.ServiceDeregister(_registrationId, cancellationToken).ConfigureAwait(false);
}
}
}
Home controller where I’m trying to call identity service from user settings service
using System.Net.Http;
using System.Text;
using System.Text.Json;
using Consul;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using System.Threading.Tasks;
using System.Linq;
[Route("api/[controller]")]
[ApiController]
public class HomeController : ControllerBase
{
private readonly IConsulClient _consulClient;
private readonly ILogger<HomeController> _logger;
private readonly IHttpContextAccessor _httpContextAccessor;
public HomeController(IConsulClient consulClient, ILogger<HomeController> logger, IHttpContextAccessor httpContextAccessor)
{
_consulClient = consulClient;
_logger = logger;
_httpContextAccessor = httpContextAccessor;
}
[HttpGet("healthcheck")]
public IActionResult Healthcheck()
{
var context = _httpContextAccessor.HttpContext; // Get the current HttpContext
var msg = $"{context.Request.Host} is healthy";
_logger.LogInformation(msg);
return Ok(msg);
}
[HttpGet("CallIdentityService")]
public async Task<IActionResult> CallIdentityService()
{
var services = await _consulClient.Agent.Services();
var identityService = services.Response.Values.FirstOrDefault(s => s.Service.Equals("IdentityService", StringComparison.OrdinalIgnoreCase));
if (identityService == null)
{
return NotFound("IdentityService not found");
}
var loginUserRequest = new LoginUserRequest
{
email = "[email protected]",
password = "123ex"
};
var client = new HttpClient();
var content = new StringContent(JsonSerializer.Serialize(loginUserRequest), Encoding.UTF8, "application/json");
try
{
_logger.LogInformation("Attempting to call IdentityService at {Url}", $"http://{identityService.Address}:{identityService.Port}/api/Account/Authorize");
var response = await client.PostAsync($"http://{identityService.Address}:{identityService.Port}/api/Account/Authorize", content);
if (response.IsSuccessStatusCode)
{
var responseContent = await response.Content.ReadAsStringAsync();
return Ok(responseContent);
}
return StatusCode((int)response.StatusCode, response.ReasonPhrase);
}
catch (HttpRequestException ex)
{
_logger.LogError(ex, "HTTP request to IdentityService failed: {Message}", ex);
return StatusCode(StatusCodes.Status500InternalServerError, "Error calling IdentityService");
}
catch (Exception ex)
{
_logger.LogError(ex, "An unexpected error occurred: {Message}", ex.Message);
return StatusCode(StatusCodes.Status500InternalServerError, "An unexpected error occurred");
}
}
}
public class LoginUserRequest
{
public string email { get; set; }
public string password { get; set; }
}
I am trying to communicate between two micro services by dynamically registering on consul and discovering from consul.
The issue appears when I work with docker. When I run consul locally instead of docker image and then registers services their, I’m not getting the connection refused error.
Full error:
2024-09-04 18:26:32 fail: HomeController[0]
2024-09-04 18:26:32 HTTP request to IdentityService failed: System.Net.Http.HttpRequestException: Connection refused (localhost:8000)
2024-09-04 18:26:32 ---> System.Net.Sockets.SocketException (111): Connection refused
2024-09-04 18:26:32 at System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.ThrowException(SocketError error, CancellationToken cancellationToken)
2024-09-04 18:26:32 at System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.System.Threading.Tasks.Sources.IValueTaskSource.GetResult(Int16 token)
2024-09-04 18:26:32 at System.Net.Sockets.Socket.<ConnectAsync>g__WaitForConnectWithCancellation|285_0(AwaitableSocketAsyncEventArgs saea, ValueTask connectTask, CancellationToken cancellationToken)
2024-09-04 18:26:32 at System.Net.Http.HttpConnectionPool.ConnectToTcpHostAsync(String host, Int32 port, HttpRequestMessage initialRequest, Boolean async, CancellationToken cancellationToken)
2024-09-04 18:26:32 --- End of inner exception stack trace ---
2024-09-04 18:26:32 at System.Net.Http.HttpConnectionPool.ConnectToTcpHostAsync(String host, Int32 port, HttpRequestMessage initialRequest, Boolean async, CancellationToken cancellationToken)
2024-09-04 18:26:32 at System.Net.Http.HttpConnectionPool.ConnectAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
2024-09-04 18:26:32 at System.Net.Http.HttpConnectionPool.CreateHttp11ConnectionAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
2024-09-04 18:26:32 at System.Net.Http.HttpConnectionPool.AddHttp11ConnectionAsync(QueueItem queueItem)
2024-09-04 18:26:32 at System.Threading.Tasks.TaskCompletionSourceWithCancellation`1.WaitWithCancellationAsync(CancellationToken cancellationToken)
2024-09-04 18:26:32 at System.Net.Http.HttpConnectionPool.SendWithVersionDetectionAndRetryAsync(HttpRequestMessage request, Boolean async, Boolean doRequestAuth, CancellationToken cancellationToken)
2024-09-04 18:26:32 at System.Net.Http.DiagnosticsHandler.SendAsyncCore(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
2024-09-04 18:26:32 at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
2024-09-04 18:26:32 at System.Net.Http.HttpClient.<SendAsync>g__Core|83_0(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationTokenSource cts, Boolean disposeCts, CancellationTokenSource pendingRequestsCts, CancellationToken originalCancellationToken)
2024-09-04 18:26:32 at HomeController.CallIdentityService() in D:githubprojservicesUserSettingsUserSettings.HttpApi.HostControllersHomeController.cs:line 57
2024-09-04 18:26:32 System.Net.Http.HttpRequestException: Connection refused (localhost:8000)
2024-09-04 18:26:32 ---> System.Net.Sockets.SocketException (111): Connection refused
2024-09-04 18:26:32 at System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.ThrowException(SocketError error, CancellationToken cancellationToken)
2024-09-04 18:26:32 at System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.System.Threading.Tasks.Sources.IValueTaskSource.GetResult(Int16 token)
2024-09-04 18:26:32 at System.Net.Sockets.Socket.<ConnectAsync>g__WaitForConnectWithCancellation|285_0(AwaitableSocketAsyncEventArgs saea, ValueTask connectTask, CancellationToken cancellationToken)
2024-09-04 18:26:32 at System.Net.Http.HttpConnectionPool.ConnectToTcpHostAsync(String host, Int32 port, HttpRequestMessage initialRequest, Boolean async, CancellationToken cancellationToken)
2024-09-04 18:26:32 --- End of inner exception stack trace ---
2024-09-04 18:26:32 at System.Net.Http.HttpConnectionPool.ConnectToTcpHostAsync(String host, Int32 port, HttpRequestMessage initialRequest, Boolean async, CancellationToken cancellationToken)
2024-09-04 18:26:32 at System.Net.Http.HttpConnectionPool.ConnectAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
2024-09-04 18:26:32 at System.Net.Http.HttpConnectionPool.CreateHttp11ConnectionAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
2024-09-04 18:26:32 at System.Net.Http.HttpConnectionPool.AddHttp11ConnectionAsync(QueueItem queueItem)
2024-09-04 18:26:32 at System.Threading.Tasks.TaskCompletionSourceWithCancellation`1.WaitWithCancellationAsync(CancellationToken cancellationToken)
2024-09-04 18:26:32 at System.Net.Http.HttpConnectionPool.SendWithVersionDetectionAndRetryAsync(HttpRequestMessage request, Boolean async, Boolean doRequestAuth, CancellationToken cancellationToken)
2024-09-04 18:26:32 at System.Net.Http.DiagnosticsHandler.SendAsyncCore(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
2024-09-04 18:26:32 at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
2024-09-04 18:26:32 at System.Net.Http.HttpClient.<SendAsync>g__Core|83_0(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationTokenSource cts, Boolean disposeCts, CancellationTokenSource pendingRequestsCts, CancellationToken originalCancellationToken)
2024-09-04 18:26:32 at HomeController.CallIdentityService() in D:githubprojservicesUserSettingsUserSettings.HttpApi.HostControllersHomeController.cs:line 57
2024-09-04 18:26:32 info: HomeController[0]
2024-09-04 18:26:32 Attempting to call IdentityService at http://localhost:8000/api/Account/Authorize
2024-09-04 18:26:36 fail: HomeController[0]
2024-09-04 18:26:36 HTTP request to IdentityService failed: System.Net.Http.HttpRequestException: Connection refused (localhost:8000)
2024-09-04 18:26:36 ---> System.Net.Sockets.SocketException (111): Connection refused
2024-09-04 18:26:36 at System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.ThrowException(SocketError error, CancellationToken cancellationToken)
2024-09-04 18:26:36 at System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.System.Threading.Tasks.Sources.IValueTaskSource.GetResult(Int16 token)
2024-09-04 18:26:36 at System.Net.Sockets.Socket.<ConnectAsync>g__WaitForConnectWithCancellation|285_0(AwaitableSocketAsyncEventArgs saea, ValueTask connectTask, CancellationToken cancellationToken)
2024-09-04 18:26:36 at System.Net.Http.HttpConnectionPool.ConnectToTcpHostAsync(String host, Int32 port, HttpRequestMessage initialRequest, Boolean async, CancellationToken cancellationToken)
2024-09-04 18:26:36 --- End of inner exception stack trace ---
2024-09-04 18:26:36 at System.Net.Http.HttpConnectionPool.ConnectToTcpHostAsync(String host, Int32 port, HttpRequestMessage initialRequest, Boolean async, CancellationToken cancellationToken)
2024-09-04 18:26:36 at System.Net.Http.HttpConnectionPool.ConnectAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
2024-09-04 18:26:36 at System.Net.Http.HttpConnectionPool.CreateHttp11ConnectionAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
2024-09-04 18:26:36 at System.Net.Http.HttpConnectionPool.AddHttp11ConnectionAsync(QueueItem queueItem)
2024-09-04 18:26:36 at System.Threading.Tasks.TaskCompletionSourceWithCancellation`1.WaitWithCancellationAsync(CancellationToken cancellationToken)
2024-09-04 18:26:36 at System.Net.Http.HttpConnectionPool.SendWithVersionDetectionAndRetryAsync(HttpRequestMessage request, Boolean async, Boolean doRequestAuth, CancellationToken cancellationToken)
2024-09-04 18:26:36 at System.Net.Http.DiagnosticsHandler.SendAsyncCore(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
2024-09-04 18:26:36 at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
2024-09-04 18:26:36 at System.Net.Http.HttpClient.<SendAsync>g__Core|83_0(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationTokenSource cts, Boolean disposeCts, CancellationTokenSource pendingRequestsCts, CancellationToken originalCancellationToken)
2024-09-04 18:26:36 at HomeController.CallIdentityService() in D:githubprojservicesUserSettingsUserSettings.HttpApi.HostControllersHomeController.cs:line 57
2024-09-04 18:26:36 System.Net.Http.HttpRequestException: Connection refused (localhost:8000)
2024-09-04 18:26:36 ---> System.Net.Sockets.SocketException (111): Connection refused
2024-09-04 18:26:36 at System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.ThrowException(SocketError error, CancellationToken cancellationToken)
2024-09-04 18:26:36 at System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.System.Threading.Tasks.Sources.IValueTaskSource.GetResult(Int16 token)
2024-09-04 18:26:36 at System.Net.Sockets.Socket.<ConnectAsync>g__WaitForConnectWithCancellation|285_0(AwaitableSocketAsyncEventArgs saea, ValueTask connectTask, CancellationToken cancellationToken)
2024-09-04 18:26:36 at System.Net.Http.HttpConnectionPool.ConnectToTcpHostAsync(String host, Int32 port, HttpRequestMessage initialRequest, Boolean async, CancellationToken cancellationToken)
2024-09-04 18:26:36 --- End of inner exception stack trace ---
2024-09-04 18:26:36 at System.Net.Http.HttpConnectionPool.ConnectToTcpHostAsync(String host, Int32 port, HttpRequestMessage initialRequest, Boolean async, CancellationToken cancellationToken)
2024-09-04 18:26:36 at System.Net.Http.HttpConnectionPool.ConnectAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
2024-09-04 18:26:36 at System.Net.Http.HttpConnectionPool.CreateHttp11ConnectionAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
2024-09-04 18:26:36 at System.Net.Http.HttpConnectionPool.AddHttp11ConnectionAsync(QueueItem queueItem)
2024-09-04 18:26:36 at System.Threading.Tasks.TaskCompletionSourceWithCancellation`1.WaitWithCancellationAsync(CancellationToken cancellationToken)
2024-09-04 18:26:36 at System.Net.Http.HttpConnectionPool.SendWithVersionDetectionAndRetryAsync(HttpRequestMessage request, Boolean async, Boolean doRequestAuth, CancellationToken cancellationToken)
2024-09-04 18:26:36 at System.Net.Http.DiagnosticsHandler.SendAsyncCore(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
2024-09-04 18:26:36 at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
2024-09-04 18:26:36 at System.Net.Http.HttpClient.<SendAsync>g__Core|83_0(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationTokenSource cts, Boolean disposeCts, CancellationTokenSource pendingRequestsCts, CancellationToken originalCancellationToken)
2024-09-04 18:26:36 at HomeController.CallIdentityService() in D:githubprojservicesUserSettingsUserSettings.HttpApi.HostControllersHomeController.cs:line 57
When you run your services on your host, they run on the same IP address. So you can use localhost
when connecting from one service to another.
When you run them on containers, each service has it’s own IP address. Docker creates a bridge network and connects each container to it. You can use the service name as the host name when connecting.
So, when connecting to identity server from Consul, you’d use the host name identityservice.httpapi.host
and port 8080.
Port mapping is used when you need to access the containers from outside the Docker bridge network created. When containers on the bridge network talk to each other, they use the unmapped port numbers. That’s why the Consul container needs to use port 8080 and not port 8000.
See this for more information.
3