aspnet / aspnet-docker

[Archived] ASP.NET Core Docker images for 1.x. Go to https://github.com/dotnet/dotnet-docker for 2.1 and up.
https://asp.net
719 stars 171 forks source link

Unable to use HttpSys with ASP.NET Core 2.0 and Windows Server Nano #398

Closed HeathJared closed 6 years ago

HeathJared commented 6 years ago

Steps to reproduce the issue

  1. Create new Empty ASP.NET Core 2.0 project in Visual Studio 2017 with Windows Docker Support
  2. Add UseHttpSys to Program.cs

    public class Program
    {
        public static void Main(string[] args)
        {
            BuildWebHost(args).Run();
        }
    
        public static IWebHost BuildWebHost(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                .UseStartup<Startup>()
                .UseHttpSys(options =>
                {
                    options.Authentication.Schemes = AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM;
                    options.Authentication.AllowAnonymous = true;
                })
                .Build();
    }
  3. Add AddAuthentication to Startup.cs

    public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddAuthentication(HttpSysDefaults.AuthenticationScheme);
        }
    
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            app.Run(async (context) =>
            {
                await context.Response.WriteAsync("Hello World!");
            });
        }
    }

docker-compose.yaml:

version: '3'

services:
  webapplication1:
    image: webapplication1
    build:
      context: .
      dockerfile: WebApplication1\Dockerfile
    environment:
      - ASPNETCORE_ENVIRONMENT=Development
    ports:
      - "5000:80"

networks:
  default:
    external:
      name: nat

dockerfile:

FROM microsoft/aspnetcore:2.0-nanoserver-1709 AS base
WORKDIR /app
EXPOSE 80

FROM microsoft/aspnetcore-build:2.0-nanoserver-1709 AS build
WORKDIR /src
COPY WebApplication1.sln ./
COPY WebApplication1/WebApplication1.csproj WebApplication1/
RUN dotnet restore -nowarn:msb3202,nu1503
COPY . .
WORKDIR /src/WebApplication1
RUN dotnet build -c Release -o /app

FROM build AS publish
RUN dotnet publish -c Release -o /app

FROM base AS final
WORKDIR /app
COPY --from=publish /app .
ENTRYPOINT ["dotnet", "WebApplication1.dll"]

Expected behavior

The service should listen on port 80 (default) internal to the container and be accessible through the host at port 5000 (specified in the compose file).

Actual behavior

Exception in Startup:

Application startup exception: System.TypeInitializationException: The type initializer for 'Microsoft.AspNetCore.Server.HttpSys.HttpApi' threw an exception. ---> System.DllNotFoundException: Unable to load DLL 'httpapi.dll': The specified module could not be found. (Exception from HRESULT: 0x8007007E)
   at Microsoft.AspNetCore.Server.HttpSys.HttpApi.HttpInitialize(HTTPAPI_VERSION version, UInt32 flags, Void* pReserved)
   at Microsoft.AspNetCore.Server.HttpSys.HttpApi.InitHttpApi(UInt16 majorVersion, UInt16 minorVersion)
   at Microsoft.AspNetCore.Server.HttpSys.HttpApi..cctor()
   --- End of inner exception stack trace ---
   at Microsoft.AspNetCore.Server.HttpSys.HttpSysListener..ctor(HttpSysOptions options, ILoggerFactory loggerFactory)
   at Microsoft.AspNetCore.Server.HttpSys.MessagePump..ctor(IOptions`1 options, ILoggerFactory loggerFactory, IAuthenticationSchemeProvider authentication)
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, ServiceProvider provider)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(IServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScoped(ScopedCallSite scopedCallSite, ServiceProvider provider)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitSingleton(SingletonCallSite singletonCallSite, ServiceProvider provider)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(IServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceProvider.<>c__DisplayClass22_0.<RealizeService>b__0(ServiceProvider provider)
   at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(Type serviceType)
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)
   at Microsoft.AspNetCore.Hosting.Internal.WebHost.EnsureServer()
   at Microsoft.AspNetCore.Hosting.Internal.WebHost.BuildApplication()
crit: Microsoft.AspNetCore.Hosting.Internal.WebHost[6]
      Application startup exception

Additional information

The build of nano server does not appear to include "httpapi.dll".

Manually copying the "httpapi.dll" into the docker container resolved this exception, but now it throws:

info: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[0]
      User profile is available. Using 'C:\Users\ContainerUser\AppData\Local\ASP.NET\DataProtection-Keys' as key repository and Windows DPAPI to encrypt keys at rest.
info: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[58]
      Creating key {404880d3-199e-406b-a0dd-2b249f9313a9} with creation date 2018-03-26 05:35:53Z, activation date 2018-03-26 05:35:53Z, and expiration date 2018-06-24 05:35:53Z.
info: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[39]
      Writing data to file 'C:\Users\ContainerUser\AppData\Local\ASP.NET\DataProtection-Keys\key-404880d3-199e-406b-a0dd-2b249f9313a9.xml'.
info: Microsoft.AspNetCore.Server.HttpSys.HttpSysListener[0]
      Start
info: Microsoft.AspNetCore.Server.HttpSys.HttpSysListener[0]
      Listening on prefix: http://+:80/
fail: Microsoft.AspNetCore.Server.HttpSys.HttpSysListener[0]
      Start
Microsoft.AspNetCore.Server.HttpSys.HttpSysException (0x80004005): Access is denied
   at Microsoft.AspNetCore.Server.HttpSys.UrlGroup.RegisterPrefix(String uriPrefix, Int32 contextId)
   at Microsoft.AspNetCore.Server.HttpSys.UrlPrefixCollection.RegisterAllPrefixes(UrlGroup urlGroup)
   at Microsoft.AspNetCore.Server.HttpSys.HttpSysListener.Start()
Unhandled Exception: Microsoft.AspNetCore.Server.HttpSys.HttpSysException: Access is denied
   at Microsoft.AspNetCore.Server.HttpSys.UrlGroup.RegisterPrefix(String uriPrefix, Int32 contextId)
   at Microsoft.AspNetCore.Server.HttpSys.UrlPrefixCollection.RegisterAllPrefixes(UrlGroup urlGroup)
   at Microsoft.AspNetCore.Server.HttpSys.HttpSysListener.Start()
   at Microsoft.AspNetCore.Server.HttpSys.MessagePump.StartAsync[TContext](IHttpApplication`1 application, CancellationToken cancellationToken)
   at Microsoft.AspNetCore.Hosting.Internal.WebHost.<StartAsync>d__26.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNetCore.Hosting.WebHostExtensions.<RunAsync>d__5.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNetCore.Hosting.WebHostExtensions.<RunAsync>d__4.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNetCore.Hosting.WebHostExtensions.Run(IWebHost host)
   at WebApplication1.Program.Main(String[] args) in c:\users\user\Source\Repos\WebApplication1\WebApplication1\Program.cs:line 11

Output of dotnet --info

C:\app>dotnet --info

Microsoft .NET Core Shared Framework Host

  Version  : 2.0.6
  Build    : 74b1c703813c8910df5b96f304b0f2b78cdf194d`

Output of docker info

Containers: 1
 Running: 1
 Paused: 0
 Stopped: 0
Images: 3
Server Version: 17.12.0-ce
Storage Driver: windowsfilter
 Windows:
Logging Driver: json-file
Plugins:
 Volume: local
 Network: ics l2bridge l2tunnel nat null overlay transparent
 Log: awslogs etwlogs fluentd gelf json-file logentries splunk syslog
Swarm: inactive
Default Isolation: hyperv
Kernel Version: 10.0 16299 (16299.15.amd64fre.rs3_release.170928-1534)
Operating System: Windows 10 Pro
OSType: windows
Architecture: x86_64
CPUs: 8
Total Memory: 31.94GiB
Name: Desktop-PC
ID: OVFT:BDJ2:YZ4D:UCHY:OE6V:NUZS:HSMY:WBXE:PFQC:5U7Q:ZBJ4:S2N2
Docker Root Dir: C:\ProgramData\Docker
Debug Mode (client): false
Debug Mode (server): true
 File Descriptors: -1
 Goroutines: 43
 System Time: 2018-03-25T22:45:33.5895979-04:00
 EventsListeners: 1
Registry: https://index.docker.io/v1/
Labels:
Experimental: true
Insecure Registries:
 127.0.0.0/8
Live Restore Enabled: false
natemcmaster commented 6 years ago

@shirhatti is httpsys supported in Nano Server for RS3?

cc @Tratcher

tabinnorway commented 6 years ago

Anything?

natemcmaster commented 6 years ago

I've used my internal email powers to ping the Nano Server team about this. Hopefully they will be able to provide an answer.

acorkery commented 6 years ago

I'm having the same issue, can't get an application to run with the combination of Nano, ASP.NET core 2.0 and HttpSys.

Bare bones 2.0 web app, with almost identical setup in Program.cs and Startup.cs mentioned above. Produces the same exception

Unhandled Exception: System.TypeInitializationException: The type initializer for 'Microsoft.AspNetCore.Server.HttpSys.HttpApi' threw an exception. ---> System.DllNotFoundException: Unable to load DLL 'httpapi.dll': The specified module could not be found. (Exception from HRESULT: 0x8007007E)

Using the latest versions of everything. OS: Windows 10 Enterprise Version 1709 (OS Build 16299.371) Docker server version: 18.05.0-ce-rc1 Image: microsoft/aspnetcore:2.0

Removing support for HttpSys from nano server seems like a big deal to me. Was this announced anywhere? Layering the auth stuff on top with another image or middleware isn't trivial.

natemcmaster commented 6 years ago

When I forwarded this to the Nano Server team, they told me httpapi should be present, however, it is apparently not. They are still looking into it. You may want to also open this issue through Windows Feedback and other Windows support channels if you have them. At the ASP.NET Core level, there doesn’t appear to be anything we can do about this Windows bug.

shirhatti commented 6 years ago

@HeathJared @tabinnorway @acorkery We heard back from the NanoServer team. The Http.Sys stack is no longer supported in NanoServer from RS3 onwards. It was one of the components that got the cut to allow us to the shrink the size of NanoServer. As such, our recommendation now would be to use Kestrel on Nano or move to ServerCore if you require HttpSysServer.

Unfortunately, there's nothing we can do about this. If you care strongly about this, I would recommend creating an issue on the Windows Server User Voice to convince them to change their minds.

HeathJared commented 6 years ago

Sorry, to necro this old closed thread, but I was hoping for a bit of confirmation.

Regarding: "As such, our recommendation now would be to use Kestrel on Nano or move to ServerCore if you require HttpSysServer."

We're already using Kestrel. The original intention for using HttpSys was to support Windows Authentication as discussed here.

It was my understanding that IIS used HttpSys under the hood, but this may be incorrect as NanoServer has support for IIS and Windows Authentication (and NanoServer no longer uses HttpSys?).

So, based on this, for projects using ASP.NET Core 2+, Kestrel, and Windows Authentication, it appears that the current recommendations are:

Is this correct?

Thanks.

shirhatti commented 6 years ago

Not quite.

Use a nanoserver/iis container with UseIISIntegration()

This will only work with Windows Server 2016. NanoServer has dropped support for IIS in future versions (Server 1709, Server 1803)

Use a microsoft/windowsservercore container with UseHttpSys()

Yes. This would be the recommended approach.

HeathJared commented 6 years ago

Okay thanks, that clears it up.

RobertPaulson90 commented 5 years ago

I'm sorry to necro this, too! But... Confused... We want to make a new project with Windows Container & Windows Authentication. Can I change the default ASP.NET Core 2.1 dockerfile to simply use microsoft/windowsservercore for the runtime?

This is what I tried but doesn't work - I'm guessing microsoft/windowsservercore doesn't have the necessary Core 2.1 runtime? Or can I not use microsoft/dotnet:2.1-sdk-nanoserver for the base build image? Hmm

FROM microsoft/windowsservercore AS base
WORKDIR /app
EXPOSE 2507
EXPOSE 44341

FROM microsoft/dotnet:2.1-sdk-nanoserver-1709 AS build
WORKDIR /src
COPY ["WebApplication5/WebApplication5.csproj", "WebApplication5/"]
RUN dotnet restore "WebApplication5/WebApplication5.csproj"
COPY . .
WORKDIR "/src/WebApplication5"
RUN dotnet build "WebApplication5.csproj" -c Release -o /app

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

FROM base AS final
WORKDIR /app
COPY --from=publish /app .
ENTRYPOINT ["dotnet", "WebApplication5.dll"]
natemcmaster commented 5 years ago

@amivit I recommend opening a new issue on https://github.com/dotnet/dotnet-docker, or commenting on https://github.com/dotnet/dotnet-docker/issues/332. We don't currently provide Windows Server Core images, but there shouldn't be any reason you cannot built it yourself. Also, this repo isn't used for 2.1 images - those moved into the microsoft/dotnet repo.