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/weatherforecastit 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/weatherforecastwhere "PORT_NUM" is any port number listed for the container when viewing with- docker ps
So how do I hit this endpoint???
Note:
- I have run docker inspect CONTAINER_NAMEand 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
 
    