ASP .NET Core WebAPI - hostowanie w IIS

0

Witam.
Drugi dzień już walcze z tym i szlak mnie trafia, bo to nie jest tak jak w tych tutorialach na necie.
Próbuje na IIS hostować WebAPI i niby konfiguracja banalna, ale jednak u mnie nie działa.

  1. Zrobiłem folder z projektem C:\inetpub\wwwroot\api
  2. Zrobiłem Publish projektu i wkleiłem do folderu z punktu 1
  3. Dodałem nową witrynę do IIS - bez nazwy hosta, adresy IP - Wszystkie nieprzypisane, port 9009
  4. W Program.cs mam
        public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
            .UseKestrel()
            .UseUrls("http://*:9009")
            .UseContentRoot(Directory.GetCurrentDirectory())
            .UseIISIntegration()
            .UseStartup<Startup>();
    }

Odpalam witrynę w przeglądarce to mam błąd:

HTTP Error 500.30 - ANCM In-Process Start Failure
Common causes of this issue:
The application failed to start
The application started but then stopped
The application started but threw an exception during startup
Troubleshooting steps:
Check the system event log for error messages
Enable logging the application process' stdout messages
Attach a debugger to the application process and inspect
For more information visit: https://go.microsoft.com/fwlink/?LinkID=2028265

Sprawdzam co ciekawego pokazują logi systemowe, są dwa błędy:

Application '/LM/W3SVC/1/ROOT' with physical root 'C:\inetpub\wwwroot\api\' failed to load clr and managed application. CLR worker thread exited prematurely
Application '/LM/W3SVC/1/ROOT' with physical root 'C:\inetpub\wwwroot\api\' hit unexpected managed exception, exception code = '0xe0434352'. Last 4KB characters of captured stdout and stderr logs:
Application startup exception: System.NullReferenceException: Object reference not set to an instance of an object.
   at API.Startup.ConfigureServices(IServiceCollection services) in C:\Users\user\source\repos\API\API\Startup.cs:line 34
--- End of stack trace from previous location where exception was thrown ---
   at Microsoft.AspNetCore.Hosting.ConventionBasedStartup.ConfigureServices(IServiceCollection services)
   at Microsoft.AspNetCore.Hosting.Internal.WebHost.EnsureApplicationServices()
   at Microsoft.AspNetCore.Hosting.Internal.WebHost.Initialize()
--- End of stack trace from previous location where exception was thrown ---
   at Microsoft.AspNetCore.Hosting.Internal.WebHost.BuildApplication()
crit: Microsoft.AspNetCore.Hosting.Internal.WebHost[6]
      Application startup exception
System.NullReferenceException: Object reference not set to an instance of an object.
   at API.Startup.ConfigureServices(IServiceCollection services) in C:\Users\user\source\repos\API\API\Startup.cs:line 34
--- End of stack trace from previous location where exception was thrown ---
   at Microsoft.AspNetCore.Hosting.ConventionBasedStartup.ConfigureServices(IServiceCollection services)
   at Microsoft.AspNetCore.Hosting.Internal.WebHost.EnsureApplicationServices()
   at Microsoft.AspNetCore.Hosting.Internal.WebHost.Initialize()
--- End of stack trace from previous location where exception was thrown ---
   at Microsoft.AspNetCore.Hosting.Internal.WebHost.BuildApplication()
crit: Microsoft.AspNetCore.Server.Kestrel[0]
      Unable to start Kestrel.
System.IO.IOException: Failed to bind to address http://[::]:9009: address already in use. ---> Microsoft.AspNetCore.Connections.AddressInUseException: Tylko jedno użycie każdego adresu gniazda (protokół/adres sieciowy/port) jest normalnie dozwolone ---> System.Net.Sockets.SocketException: Tylko jedno użycie każdego adresu gniazda (protokół/adres sieciowy/port) jest normalnie dozwolone
   at System.Net.Sockets.Socket.UpdateStatusAfterSocketErrorAndThrowException(SocketError error, String callerName)
   at System.Net.Sockets.Socket.DoBind(EndPoint endPointSnapshot, SocketAddress socketAddress)
   at System.Net.Sockets.Socket.Bind(EndPoint localEP)
   at Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.SocketTransport.BindAsync()
   --- End of inner exception stack trace ---
   at Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.SocketTransport.BindAsync()
   at Microsoft.AspNetCore.Server.Kestrel.Core.KestrelServer.<>c__DisplayClass21_0`1.<<StartAsync>g__OnBind|0>d.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.AddressBinder.BindEndpointAsync(ListenOptions endpoint, AddressBindContext context)
   --- End of inner exception stack trace ---
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.AddressBinder.BindEndpointAsync(ListenOptions endpoint, AddressBindContext context)
   at Microsoft.AspNetCore.Server.Kestrel.Core.ListenOptions.BindAsync(AddressBindContext context)
   at Microsoft.AspNetCore.Server.Kestrel.Core.AnyIPListenOptions.BindAsync(AddressBindContext context)
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.AddressBinder.AddressesStrategy.BindAsync(AddressBindContext context)
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.AddressBinder.BindAsync(IServerAddressesFeature addresses, KestrelServerOptions serverOptions, ILogger logger, Func`2 createBinding)
   at Microsoft.AspNetCore.Server.Kestrel.Core.KestrelServer.StartAsync[TContext](IHttpApplication`1 application, CancellationToken cancellationToken)

Nie mam nic innego włączonego na porcie 9009. Nie mam zielonego pojęcia co robię źle...

PS.
Próbuje to uruchomić na Windows 10 Pro 1809 (17763.253).
ASP .NET Core jest w wersji 2.2

1

Masz .UseKestrel().UseUrls("http://*:9009"), czyli próbujesz wystartować wbudowany serwer (Kestrel) na porcie 9009, a już IIS słucha na tym porcie, więc nie może wystartować.

Jeżeli chcesz korzystać z IIS i "in-process hosting", to musisz tam mieć .UseIIS(), bo inaczej IIS działa tylko jako reverse-proxy dla Kestrela. https://docs.microsoft.com/pl-pl/aspnet/core/host-and-deploy/iis/?view=aspnetcore-2.2

0

Zmieniłem na .UseIIS() i teraz mam błąd co mi bardzo dużo mówi:

An error occurred while starting the application.
.NET Core 4.6.27207.03 X64 v4.0.0.0 | Microsoft.AspNetCore.Hosting version 2.2.0-rtm-35687  |  Microsoft Windows 10.0.17763  |  Need help?

W logach systemowych mam:

Application 'C:\inetpub\wwwroot\api\' started the coreclr in-process successfully.
0

Dodatkowo musisz pamiętać żeby ustawić na puli aplikacji Wersję Środowiska na "Bez kodu zarządzalnego" i mieć doinstalowane odpowiednie paczki dla .net core w systemie.

0

@Bogu: Mam paczki z .net core i mam w puli wybraną opcję Bez kodu zarządzalnego

PS.
Jak w consoli odpalę dotnet API.dll to się wszystko poprawnie uruchamia i działa.

0

Nie brakuje Ci tam czasem pliku web.config?

0

Nie brakuje

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <location path="." inheritInChildApplications="false">
    <system.webServer>
      <handlers>
        <add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModuleV2" resourceType="Unspecified" />
      </handlers>
      <aspNetCore processPath="dotnet" arguments=".\API.dll" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" hostingModel="InProcess" />
    </system.webServer>
  </location>
</configuration>
<!--ProjectGuid: 846eed54-fc74-4a39-8bda-1db340f3e36d-->
0

Głupie pytanie, ale działało Ci to wcześniej? Ja od wczoraj mam podobny problem, DLLki zbudowane w release mode rzucają ten sam błąd, mimo że wcześniej działało jak należy. Wrzucasz pod IIS debug czy release build?

0

Nie miałem tego wcześniej na IIS, ponieważ byłem w trakcie pisania. Skończyłem już jakąś część i chciałem to udostępnić na zewnątrz do testów i takie jaja. Publish robię w release.

0

Czy serwer IIS ma zainstalowaną tą samą wersję .Net Core co wersja pod którą budujesz kod?

0

Chyba tak - AspNetCoreModule i AspNetCoreModuleV2.

1

Najprawdopodobniej bug jest w wersji V2, ponieważ jak w pliku web.config zmienisz modules="AspNetCoreModuleV2" na modules="AspNetCoreModule" to działa bez zająknięcia...

0

@AdamWox: aby dokladnie dowiedziec sie jaki blad sie pojawia, zmien stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" na true, upewnij sie masz utworzony folder logs oraz ze ten folder ma write i read permissions. IIS utworzy tam plik z bledem.

0

@Aventus: zmieniłem na V2 i włączyłem te logi. Oto treść magicznego błędu:

Application startup exception: System.NullReferenceException: Object reference not set to an instance of an object.
   at OptimoAPI.Startup.ConfigureServices(IServiceCollection services) in C:\Users\Adam\source\repos\OptimoAPI\OptimoAPI\Startup.cs:line 52
--- End of stack trace from previous location where exception was thrown ---
   at Microsoft.AspNetCore.Hosting.ConventionBasedStartup.ConfigureServices(IServiceCollection services)
   at Microsoft.AspNetCore.Hosting.Internal.WebHost.EnsureApplicationServices()
   at Microsoft.AspNetCore.Hosting.Internal.WebHost.Initialize()
--- End of stack trace from previous location where exception was thrown ---
   at Microsoft.AspNetCore.Hosting.Internal.WebHost.BuildApplication()
crit: Microsoft.AspNetCore.Hosting.Internal.WebHost[6]
      Application startup exception
System.NullReferenceException: Object reference not set to an instance of an object.
   at OptimoAPI.Startup.ConfigureServices(IServiceCollection services) in C:\Users\Adam\source\repos\OptimoAPI\OptimoAPI\Startup.cs:line 52
--- End of stack trace from previous location where exception was thrown ---
   at Microsoft.AspNetCore.Hosting.ConventionBasedStartup.ConfigureServices(IServiceCollection services)
   at Microsoft.AspNetCore.Hosting.Internal.WebHost.EnsureApplicationServices()
   at Microsoft.AspNetCore.Hosting.Internal.WebHost.Initialize()
--- End of stack trace from previous location where exception was thrown ---
   at Microsoft.AspNetCore.Hosting.Internal.WebHost.BuildApplication()
Hosting environment: Production
Content root path: c:\windows\system32\inetsrv
Application started. Press Ctrl+C to shut down.
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
      Request starting HTTP/1.1 GET http://localhost:9009/  
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
      Request finished in 25.7203ms 500 text/html; charset=utf-8
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
      Request starting HTTP/1.1 GET http://localhost:9009/favicon.ico  
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
      Request finished in 0.5432ms 500 text/html; charset=utf-8
0

Standardowy blad null reference. Musisz sam zobaczyc co tam moze wywalac bo to sie dzieje w Twoim kodzie (Startup.ConfigureServices). Jest ten blad Ci nie wyskakuje przy odpalaniu API przez Visual Studio (IIS Express) to obstawiam ze wplyw moze miec konfiguracja (IConfiguration)- zaznaczam ze strzelam w ciemno. Czy robisz publish jako debug czy release? Czy ladujesz konfiguracje z pliku recznie? Jesli robisz publish pod release, to urucham apliacje w VS rowniez jako release i zobaczy czy pojawia sie ten blad.

Hosting environment: Production

Prawdopodobnie to ma wplyw. Sprobuj odzwierciedlic to samo srodowisko przy uruchamianiu przez VS.

0

Na release jest null exception. Mam dodaną opcje z włączeniem corsów.

An error occurred while starting the application.
NullReferenceException: Object reference not set to an instance of an object.

OptimoAPI.Startup.ConfigureServices(IServiceCollection services) in Startup.cs, line 34
OptimoAPI.Startup.ConfigureServices(IServiceCollection services) in Startup.cs
-
        public IConfiguration Configuration { get; }
        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddCors(options =>
            {
                options.AddPolicy("AllowMyOrigin", builder =>
                {
                    builder.AllowAnyOrigin();
                });
            });
Microsoft.AspNetCore.Hosting.ConventionBasedStartup.ConfigureServices(IServiceCollection services)
Microsoft.AspNetCore.Hosting.Internal.WebHost.EnsureApplicationServices()
Microsoft.AspNetCore.Hosting.Internal.WebHost.Initialize()
Microsoft.AspNetCore.Hosting.Internal.WebHost.BuildApplication()

Podświetla się na czerwono w lini services.AddCors(options =>

Jeśli wyrzucę AddCors i UseCors to mam to:

An error occurred while starting the application.
NullReferenceException: Object reference not set to an instance of an object.
OptimoAPI.Startup.ConfigureServices(IServiceCollection services)

NullReferenceException: Object reference not set to an instance of an object.
OptimoAPI.Startup.ConfigureServices(IServiceCollection services)
Microsoft.AspNetCore.Hosting.ConventionBasedStartup.ConfigureServices(IServiceCollection services)
Microsoft.AspNetCore.Hosting.Internal.WebHost.EnsureApplicationServices()
Microsoft.AspNetCore.Hosting.Internal.WebHost.Initialize()
Microsoft.AspNetCore.Hosting.Internal.WebHost.BuildApplication()

Jeśli zmienie ASPNETCORE_ENVIRONMENT na Production to pokazuje mi Visual to samo co IIS

An error occurred while starting the application.
.NET Core 4.6.27207.03 X64 v4.0.0.0  | Microsoft.AspNetCore.Hosting version 2.2.0-rtm-35687  |  Microsoft Windows 10.0.17763  |  Need help?
0

Jeśli zmienie ASPNETCORE_ENVIRONMENT na Production to pokazuje mi Visual to samo co IIS

Czyzby jednak problem byl gdzies indziej niz w IIS? ;) W ktorym konkretnie miejscu rzuca null reference exception?

0

Nie rzuca null reference. W przeglądarce tylko pokazuje to co napisałem wyżej. Visual nie sypie błędem ani na release, ani na debug. Jeśli API jest w trybie Development to przeglądarka pokazuje błędy z null reference. Jeśli API jest w trybie Production to pokazuje tylko An error occurred while starting the application.

0

Czy masz jakas logike dzialajaca na podstawie srodowiska? Brzmi jakbys cos przeoczyl w kodzie dzialajacym pod Production. Czy ten kod:

public IConfiguration Configuration { get; }

jest gdzies uzywany? Czy ma przypisana wartosc?

0

Mój Startup.cs. Ja tylko dopisuje potrzebne rzeczy do IServiceCollection. Wartości jakie przyjmuje IConfiguration były już od początku stworzenia projektu, domyślnie.

    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

            var appSettingsSelection = Configuration.GetSection("AppSettings");
            services.Configure<AppSettings>(appSettingsSelection);
            var appSettings = appSettingsSelection.Get<AppSettings>();

            var appConfigSection = Configuration.GetSection("AppConfig");
            services.Configure<AppConfig>(appConfigSection);

            var sqlConfigSection = Configuration.GetSection("SqlConfig");
            services.Configure<SqlConfig>(sqlConfigSection);

            var key = Encoding.ASCII.GetBytes(appSettings.Secret);
            services.AddAuthentication(x =>
            {
                x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            })
            .AddJwtBearer(x =>
            {
                x.RequireHttpsMetadata = false;
                x.SaveToken = true;
                x.TokenValidationParameters = new TokenValidationParameters
                {
                    ValidateIssuerSigningKey = true,
                    IssuerSigningKey = new SymmetricSecurityKey(key),
                    ValidateIssuer = false,
                    ValidateAudience = false
                };
            });

            services.AddScoped<IUserService, UserService>();
        }

        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseHsts();
            }
            app.UseHttpsRedirection();
            app.UseAuthentication();
            app.UseMvc();
        }
    }
0

Ciezko wrozyc z fusow, ale jest tu poro miejsc ktore moga to rzucac. Nadal wydaje mi sie ze to moze miec cos wspolnego z niezaladowana konfiguracja. Jak wyglada Program.cs? Sprobuj jeszcze na szybko takiej rzeczy: zbuduj kod, natepnie w folderze bin z ktorego bedziesz go odpalal zmien appsettings.json na appsettings.production.json. Odpal aplikacje, oczywiscie upewniajac sie ze srodowisko jest ustawione na production.

Ewentualnie sprobuj wykomentowac kod z ConfigureServices kawalek po kawalku i zobaczy czy/kiedy aplikacja zacznie dzialac.

0
var key = Encoding.ASCII.GetBytes(appSettings.Secret);

W appsetttings.json mam objekt, który przechowuje klucz do JWT

  "AppSettings": {
    "Secret": "superextratajnykluczdoapi"
  },

Jeśli wpisze statycznie ten klucz to działa

var key = Encoding.ASCII.GetBytes("superextratajnykluczdoapi");

W tutorialu było, że tam takie rzeczy się trzyma, ale to chyba nie jest zbyt bezpieczne? Czy nie ma znaczenia?

0

Po raz kolejny atakujesz symptom a nie przyczynę ;) skoro tam Ci wywala, to znaczy że nie ładuje Ci prawidłowo obiektu appSetings pod konkretnym środowiskiem. Trzeba więc sprawdzić dla czego tak się dzieje. Takie rzeczy powinny właśnie być ładowane z pliku. Próbowałeś zmienić nazwę pliku appsetings.json tak jak radzilem?

0

Tak, nic to nie dało. Próbowałem jeszcze ze stacków sposób:

    public class Program
    {
        public static void Main(string[] args)
        {
            CreateWebHostBuilder(args)
                .Build()
                .Run();
        }

        public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
        .UseIIS()
        .UseUrls("http://*:9009")
        .UseContentRoot(Directory.GetCurrentDirectory())
        .ConfigureAppConfiguration((builderContext, config) =>
        {
            config.AddJsonFile("appsettings.json", optional: true);
            config.AddJsonFile($"appsettings.Production.json", optional: true);
        })
        .UseStartup<Startup>();
    }

Podobno domyślnie w release i production nie ładuje tego pliku i trzeba mu podać. Teraz mam błąd:

HTTP Error 500.30 - ANCM In-Process Start Failure

PS.
To co tutaj wrzucam w dalszym ciągu wszystko testuje pod VS nie w IIS.

0

Jednej rzeczy nie rozumiem- żadnego wyjątku Ci nie rzuca w Visual Studio? Włączyłeś Common Language Runtime Exceptions? Jeśli dobrze pamiętam żeby to włączyć musisz otworzyć Debug > Windows > exceptions.

Swoją drogą chyba nie potrzebujesz wołać UseIIS().

0
    public class Program
    {
        public static void Main(string[] args)
        {
            CreateWebHostBuilder(args)
                .Build()
                .Run();
        }

        public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
        .UseUrls("http://*:9009")
        .UseContentRoot(Directory.GetCurrentDirectory())
        .UseStartup<Startup>();
    }
  1. Usunąłem to co niepotrzebne z Program.cs
  2. Wszedłem do Debug -> Windows -> Exception Settings i zaznaczyłem opcję System.NullReferenceException
    VS rzucił wyjątkiem, że mam null w methodzie Main.
    StackTrace:
   at OptimoAPI.Startup.ConfigureServices(IServiceCollection services)
0

Ustaw breakpoint i zobacz "ręcznie" co tam jest nullem.

0

Wychodzi na to, że wstrzykiwanie IConfiguration nie działa w NET Core jeśli apka pracuje w trybie Production.

public Startup(IConfiguration conf)
{
      Configuration = conf;
}
public IConfiguration Configuration { get; }

Trzeba użyć ConfigurationBuilder, aby to wszystko działało.

public Startup(IHostingEnvironment env)
{
     var builder = new ConfigurationBuilder()
          .AddJsonFile("appsettings.json")
          .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
          .AddEnvironmentVariables();
     Configuration = builder.Build();
}
public IConfiguration Configuration { get; set; }

Zrobiłem sobie na szybko akcję, która zwraca nazwę instancji SQL, jaka jest zapisana w pliku appsettings.json i wszystko teraz pokazuje poprawnie i nie ma żadnych błędów.

0

Czyli przyczyna się zgadza z tym co mówiłem.

Zrobiłem sobie na szybko akcję, która zwraca nazwę instancji SQL, jaka jest zapisana w pliku appsettings.json

To chyba powinno być wyciąganie z tego drugiego pliku jeśli masz to uruchomione jako Production?

Widzisz, na przyszłość nie obwiniaj z góry czegoś nie będąc pewnym czy faktycznie to jest przyczyną :)

0

To nie była kwestia obwiniania. Błąd i problem z API tylko utwierdził mnie w tym, że nie chce IIS i mimo iż to działa ja w dalszym ciągu go nie chce :D Problem w tym, że nie ma alternatywy. Niestety jestem zmuszony z tego korzystać.
Reasumując - nie powinno być tak, że aplikacja działa w VS, a nie działa po opublikowaniu do IIS. Pisząc cokolwiek, nie czepiam się już API, powinno po wydaniu działać tak jak działało przy tworzeniu. Oczywiście na tej samej maszynie. Idąc dalej. Uruchamiając opublikowaną aplikacje za pomocą komendy dotnet, wszystko działa. Czyli co? IIS nie hostuje apki w dotnet? To jak hostuje?
Coś tutaj jest ewidentnie pomieszane i mimo, iż problemy z moim API nie są z powodu IIS to durny tryb (Production/Development) zmienia tak środowisko aplikacji, że nie ładuje pliku konfiguracyjnego... Paradox ;)

1 użytkowników online, w tym zalogowanych: 0, gości: 1