skip to Main Content

I’m trying to deploy my application which consists of Angular and ASP.NET. I’ve managed to successfully publish the app with docker. When I launch application with docker and call any method from swagger I get 404. How can I fix this?

Maybe it is because docker is launched on localhost and tries to make request to localhost, not the container. Nevertheless, I think that if the localhost was launched successfully the requests should also work(?).

One more question is – how do I launch my Angular app with docker? When I run the docker, api is the only project that is launched. You may notice that I’ve excluded Angular app from csproj because I’ve added additional steps to build it in dockerfile.

Please feel free to ask me any details.

Additional Information:
enter image description here

[Route("api/[controller]")]
[ApiController]
public class PingController : ControllerBase
{
    [HttpGet("ping")]
    public int Ping()
    {
        return 1;
    }
}

dockerfile:

FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
    # Setup NodeJs
    RUN apt-get update && 
        apt-get install -y wget && 
        apt-get install -y gnupg2 && 
        wget -qO- https://deb.nodesource.com/setup_16.x | bash - && 
        apt-get install -y build-essential nodejs
    # End setup
WORKDIR /app
EXPOSE 80
EXPOSE 443

FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
WORKDIR /src
COPY ["SelfWebsiteApi/SelfWebsiteApi.csproj", "SelfWebsiteApi/"]
RUN dotnet restore "SelfWebsiteApi/SelfWebsiteApi.csproj"
COPY . .
WORKDIR "/src/SelfWebsiteApi"
RUN dotnet build "SelfWebsiteApi.csproj" -c Release -o /app/build

FROM build AS publish
RUN dotnet publish "SelfWebsiteApi.csproj" -c Release -o /app/publish



#Angular build
FROM node as nodebuilder

# set working directory
RUN mkdir /usr/src/app
WORKDIR /usr/src/app

# add `/usr/src/app/node_modules/.bin` to $PATH
ENV PATH /usr/src/app/node_modules/.bin:$PATH

# install and cache app dependencies
COPY SelfWebsiteApi/SelfWebsiteAngular/package.json /usr/src/app/package.json
RUN npm install
RUN npm install -g @angular/cli --unsafe

# add app
COPY SelfWebsiteApi/SelfWebsiteAngular/. /usr/src/app

RUN npm run build --prod

#End Angular build

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
RUN mkdir -p /app/SelfWebsiteAngular/dist
COPY --from=nodebuilder /usr/src/app/dist/. /app/SelfWebsiteAngular/dist/
ENTRYPOINT ["dotnet", "SelfWebsiteApi.dll"]

csproj:

<Project Sdk="Microsoft.NET.Sdk.Web">

    <PropertyGroup>
        <TargetFramework>net6.0</TargetFramework>
        <Nullable>enable</Nullable>
        <ImplicitUsings>enable</ImplicitUsings>
        <SpaRoot>SelfWebsiteAngular</SpaRoot>
        <DefaultItemExcludes>$(DefaultItemExcludes);$(SpaRoot)node_modules**</DefaultItemExcludes>
        <UserSecretsId>57cd274b-65dd-4fa0-938b-cdb4fb135876</UserSecretsId>
        <DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
    </PropertyGroup>

    <ItemGroup>
        <PackageReference Include="AutoMapper" Version="11.0.1" />
        <PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="11.0.0" />
        <PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="6.0.5" />
        <PackageReference Include="Microsoft.AspNetCore.SpaServices.Extensions" Version="6.0.6" />
        <PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.5" />
        <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="6.0.5" />
        <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="6.0.5">
            <PrivateAssets>all</PrivateAssets>
            <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
        </PackageReference>
        <PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.15.1" />
        <PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="6.0.4" />
        <PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.3" />
    </ItemGroup>

    <ItemGroup>
        <Content Remove="$(SpaRoot)**" />
        <None Remove="$(SpaRoot)**" />
        <None Include="$(SpaRoot)**" Exclude="$(SpaRoot)node_modules**" />
    </ItemGroup>

    <!--<Target Name="PublishRunWebpack" AfterTargets="ComputeFilesToPublish">
        <Exec WorkingDirectory="$(SpaRoot)" Command="npm install" />
        <Exec WorkingDirectory="$(SpaRoot)" Command="npm run build - -prod" />

        <ItemGroup>
            <DistFiles Include="$(SpaRoot)dist**" />
            <ResolvedFileToPublish Include="@(DistFiles->'%(FullPath)')" Exclude="@(ResolvedFileToPublish)">
                <RelativePath>%(DistFiles.Identity)</RelativePath>
                <CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
                <ExcludeFromSingleFile>true</ExcludeFromSingleFile>
            </ResolvedFileToPublish>
        </ItemGroup>
    </Target>-->
</Project>

program.cs:

var builder = WebApplication.CreateBuilder(args);
var origin = builder.Configuration.GetValue<string>("SelfWebsiteAngular:Name");
var angularLink = builder.Configuration.GetValue<string>("SelfWebsiteAngular:Link");

builder.Services.AddCors(options =>
{
    options.AddPolicy(origin, builder =>
    {
        builder.WithOrigins(angularLink)
        //.AllowAnyOrigin()
        .AllowAnyMethod()
        .AllowAnyHeader();
    });
});
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddDbContext<SelfWebsiteContext>(options =>
    options.UseSqlServer(builder.Configuration.GetConnectionString("SelfWebsiteDatabase")));
builder.Services
    .AddAuthentication(options =>
    {
        options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
        options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
    })
    .AddJwtBearer(options =>
    {
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuer = true,
            ValidateAudience = true,
            ValidateLifetime = true,
            ValidateIssuerSigningKey = true,
            ValidIssuer = builder.Configuration.GetValue<string>("Settings:ServerLink"),
            ValidAudience = builder.Configuration.GetValue<string>("Settings:ServerLink"),
            IssuerSigningKey = new SymmetricSecurityKey(
                Encoding.UTF8.GetBytes(
                    builder.Configuration.GetValue<string>("Settings:Authorization:SymmetricSecurityKey"))),
        };
    });

builder.Services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies());

builder.Services.AddTransient<ITokenService, TokenService>();
builder.Services.AddTransient<IAuthService, AuthService>();
builder.Services.AddTransient<IResumeService, ResumeService>();
builder.Services.AddTransient<ILinkService, LinkService>();
builder.Services.AddTransient<ISectionService, SectionService>();
builder.Services.AddSingleton<IMapperProvider, MapperProvider>();
builder.Services.AddSpaStaticFiles(configuration =>
{
    configuration.RootPath = "SelfWebsiteAngular/dist";
});

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseStaticFiles();
//if (!app.Environment.IsDevelopment())
//{
    app.UseSpaStaticFiles();
//}

app.UseSpa(spa =>
{
    // To learn more about options for serving an Angular SPA from ASP.NET Core,
    // see https://go.microsoft.com/fwlink/?linkid=864501

    spa.Options.SourcePath = "SelfWebsiteAngular";

    //if (app.Environment.IsDevelopment())
    //{
        spa.UseAngularCliServer(npmScript: "start");
        // spa.UseProxyToSpaDevelopmentServer("http://localhost:4200");
    //}
});

app.UseHttpsRedirection();
app.UseRouting();
app.UseCors(origin);
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();

2

Answers


  1. Swagger is, by default, only available when the environment is ‘Development’. Containers, by default, aren’t development.

    The code that does that is this in Program.cs

    if (app.Environment.IsDevelopment())
    {
        app.UseSwagger();
        app.UseSwaggerUI();
    }
    

    There are multiple ways to make Swagger available in a container.

    You can permanently make it available by removing the if in the above code so it becomes

    app.UseSwagger();
    app.UseSwaggerUI();
    

    You can also set the environment in the image to Development by setting ASPNETCORE_ENVIRONMENT like this

    FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
    ENV ASPNETCORE_ENVIRONMENT=Development
        # Setup NodeJs
        RUN apt-get update && 
            apt-get install -y wget && 
            apt-get install -y gnupg2 && 
            wget -qO- https://deb.nodesource.com/setup_16.x | bash - && 
            apt-get install -y build-essential nodejs
        # End setup
    WORKDIR /app
    EXPOSE 80
    EXPOSE 443
    

    A third option is to pass the environment variable on your docker run command by adding an -e ASPNETCORE_ENVIRONMENT=Development option to the command.

    Which solution you should choose depends on how permanently you want to make Swagger available.

    Login or Signup to reply.
  2. Try

    app.UseRouting();

    and also then

    app.UseAuthorization();

    because for me worked normally without this configuration in debug mode but it didn’t work in Docker.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search