I have two projects:
- UI (a .NET Core 3.1 MVC font-end)
- API (a .NET Core 3.1 Web API)
that each run in two separate containers. They share a docker-compose file that builds them both. From the UI project, I want to be able to make an AJAX call to hit the endpoint in the API project. What is the URL that will hit my endpoint?
What I have tried:
- If I run the API project alone with IIS, I can successfully hit the endpoint by navigating to
https://localhost:49239/weatherforecast
. But, again, I want to hit this endpoint by calling it from the client within the UI project. - If I use the docker-compose to launch both containers, then from the UI project click the button that executes my AJAX call to the endpoint
https://localhost:49239/weatherforecast
it does not work. I have tried many variations to the host part of the URL to reach it.
According to Networking in Compose
Compose sets up a single network for your app. Each container for a service joins the default network and is both reachable by other containers on that network and is discoverable by them at a hostname identical to the container name.
With that, I have also tried many variations of host URL such as https://api:49243/weatherforecast
where "api" is the name of my docker image and "49243" is the port listed by docker ps
. I have also tried:
https://api:80/weatherforecast
https://api:433/weatherforecast
https://api:PORT_NUM/weatherforecast
where "PORT_NUM" is any port number listed for the container when viewing withdocker ps
So how do I hit this endpoint???
Note:
- I have run
docker inspect CONTAINER_NAME
and I know that both containers are on the same network.
Files:
- UI > Index.cshtml:
@{
ViewData["Title"] = "Home Page";
}
<div class="text-center">
<h1 class="display-4">Welcome</h1>
<p>Learn about <a href="https://learn.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>
<button type="button" class="btn btn-primary" onclick="callAPI()">Call API</button>
</div>
@section scripts {
<script>
function callAPI() {
console.log("calling API...");
$.ajax({
url: `https://api:49221/weatherforast/get`,
method: 'GET',
success: function (data) {
console.log(data);
},
error: function (error) {
console.log(error);
}
});
}
</script>
}
- UI > Dockerfile:
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-buster-slim AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443
FROM mcr.microsoft.com/dotnet/core/sdk:3.1-buster AS build
WORKDIR /src
COPY ["UI/UI.csproj", "UI/"]
RUN dotnet restore "UI/UI.csproj"
COPY . .
WORKDIR "/src/UI"
RUN dotnet build "UI.csproj" -c Release -o /app/build
FROM build AS publish
RUN dotnet publish "UI.csproj" -c Release -o /app/publish
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "UI.dll"]
- API > WeatherForecastController.cs:
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace API.Controllers
{
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
private readonly ILogger<WeatherForecastController> _logger;
public WeatherForecastController(ILogger<WeatherForecastController> logger)
{
_logger = logger;
}
[HttpGet]
public IEnumerable<WeatherForecast> Get()
{
var rng = new Random();
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = rng.Next(-20, 55),
Summary = Summaries[rng.Next(Summaries.Length)]
})
.ToArray();
}
}
}
- API > Dockerfile:
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-buster-slim AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443
FROM mcr.microsoft.com/dotnet/core/sdk:3.1-buster AS build
WORKDIR /src
COPY ["API/API.csproj", "API/"]
RUN dotnet restore "API/API.csproj"
COPY . .
WORKDIR "/src/API"
RUN dotnet build "API.csproj" -c Release -o /app/build
FROM build AS publish
RUN dotnet publish "API.csproj" -c Release -o /app/publish
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "API.dll"]
- docker-compose:
version: '3.4'
services:
ui:
image: ${DOCKER_REGISTRY-}ui
build:
context: .
dockerfile: UI/Dockerfile
api:
image: ${DOCKER_REGISTRY-}api
build:
context: .
dockerfile: API/Dockerfile
- To better understand the solution structure, here is a screen shot of my Solution Explorer