ASP.NET Core .NET 6 Preview 7 Windows Service - c#

I created a new ASP.NET Core project with Visual Studio 2022 Preview and I am trying to run it as a Windows Service. I downloaded the latest Microsoft.Extensions.Hosting.WindowsServices package (6.0.0-preview.7.21377.19).
When researching online the function .UseWindowsService() goes into CreateHostBuilder method. But in the new template it looks different. I cannot understand where I should call .UseWindowsService in the new template. This is my current code, it looks like the service is starting but then when I browse to localhost:5000 it gives me 404 error
using Microsoft.OpenApi.Models;
using Microsoft.Extensions.Hosting.WindowsServices;
var builder = WebApplication.CreateBuilder(args);
builder.Host.UseWindowsService(); // <--- Added this line
// Add services to the container.
builder.Services.AddControllers();
builder.Services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new() { Title = "MyWindowsService", Version = "v1" });
});
var app = builder.Build();
// Configure the HTTP request pipeline.
if (builder.Environment.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseSwagger();
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "MyWindowsService v1"));
}
app.UseAuthorization();
app.MapControllers();
app.Run();
I published my service exe like this
dotnet publish -c Release -r win-x64 --self-contained

Since simply using
builder.Host.UseWindowsService();
will not work with WebApplication.CreateBuilder() (see), but instead will throw the exception
Exception Info: System.NotSupportedException: The content root changed from "C:\Windows\system32\" to "...". Changing the host configuration using WebApplicationBuilder.Host is not supported. Use WebApplication.CreateBuilder(WebApplicationOptions) instead.
or rather will cause this error
Start-Service : Service 'Service1 (Service1)' cannot be started due to the following error: Cannot start service Service1 on computer '.'.
when trying to start the Service with Start-Service in PowerShell, I found a workaround that worked for me
using Microsoft.Extensions.Hosting.WindowsServices;
var options = new WebApplicationOptions
{
Args = args,
ContentRootPath = WindowsServiceHelpers.IsWindowsService() ? AppContext.BaseDirectory : default
};
var builder = WebApplication.CreateBuilder(options);
builder.Host.UseWindowsService();
here:
An asp.net core web api application, using "UseWindowsService", reports an error “System.NotSupportedException: The content root changed. Changing the host configuration is not supported ” when starting the service

The following coding sets the lifetime to WindowsServiceLifetime and enables logging to the event log. In most cases this should be all you need to run the app as a Windows Service.
if (WindowsServiceHelpers.IsWindowsService())
{
appBuilder.Services.AddSingleton<IHostLifetime, WindowsServiceLifetime>();
appBuilder.Logging.AddEventLog(settings =>
{
if (string.IsNullOrEmpty(settings.SourceName))
{
settings.SourceName = appBuilder.Environment.ApplicationName;
}
});
}

Related

Publishing ASP.NET Core Web API on IIS - page not found error (404)

This issue is similar to this question previously asked:
Publishing and hosting Web API developed in .net core through IIS
However I am following everything in the guidelines:
.NET Core hosting bundle is installed on the server [DONE]
Your application pool .NET CLR version is set to "No Managed Code" [DONE]
The site is the standard ASP.NET Core Web API with a WeatherForecast site:
The publish feature is set as standard as well:
My IIS application pool is also set:
When I test my connection in IIS it also says everything is looking good.
Starting the IIS app still gives me a page not found, when I access it. Now if I add an index.html (http://mysite.dk/index.html) in the root folder, I get a hit.
However shouldn't my swagger start up automatically? Trying to access it explicitly (mysite.dk/swagger/index.html) also gives me a 404 error.
My 'Program.cs':
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.UseDeveloperExceptionPage();
app.Run();
Please what am I missing?

Asp.Net Core Web Api and Vue.js client with IIS

I'm trying to create an app with Asp.Net Core (.NET 6.0) as backend and Vue.js as frontend. I've created the .NET project inside Visual Studio 2022, added SPA Extensions and finally my Program.cs file look like this:
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
// Used by single page application requirements.
builder.Services.AddSpaStaticFiles(options =>
{
options.RootPath = "wwwroot";
});
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.UseStaticFiles();
if (!app.Environment.IsDevelopment())
{
app.UseSpaStaticFiles();
}
app.UseSpa(configuration =>
{
configuration.Options.SourcePath = "wwwroot";
if (app.Environment.IsDevelopment())
{
configuration.UseProxyToSpaDevelopmentServer("http://localhost:5002");
}
});
app.Run();
Deploying code with setttings:
Delete existing files
Configuration Release
Target net6.0 Framework
Target win-x64 Runtime
Produce me a folder containing wwwroot folder with frontend files and many files for my backend application. I put them in an application inside iis server with an application pool configured as:
.NET CLR Version 4.0
Integrated pipeline mode
But my application can only load index.html file but not any .js or .css.
My application has a binding like this:
https://app.domain.it/app-name and she try to open https://app.domain.it/filename.ext file each time, failing, since file is in a https://app.domain.it/app-name/wwwroot/file.ext and he's searching for https://app.domain.it/file.ext
Anyone could help me?
Edit 1: since I've selected Self-contained mode, I don't need the .NET 6 runtime installed on server host, right?
My recommendation is to create two different Application Pools and then deploy the .net core solution as your API (a) and the vue-app as your UI (b) separately.
(a) Standard Deployment with neither a project reference to UI-project nor a configuration of the pipeline regarding Static and default Files (app.UseStaticFiles(); app.UseDefaultFiles(); not necessary )
(b) right click on vue project in VS and "Open in Terminal" -> then npm run build -> then go to dist folder and copy content to physical path for respective application pool on IIS
Solution worked for me. Let me know if it is a solution for you as well and if you have any questions. Hope I could help you.

ASP.NET Core (.Net 6) Web Application throws System.NotSupportedException when run as a service. (Service will not start)

When I attempt to run my .Net Web Application as a Windows Service, it does not start. It works if I just run the executable but mysteriously fails when attempting to run as a service. I have logged the relevant error messages and reported my solution below.
The following exception is in the event viewer.
Exception in Event Viewer
Application: WebApplication5.exe
CoreCLR Version: 6.0.222.6406
.NET Version: 6.0.2
Description: The process was terminated due to an unhandled exception.
Exception Info: System.NotSupportedException: The content root changed from "C:\Windows\system32" to "C:\Program Files (x86)\My Company\webapp5". Changing the host configuration using WebApplicationBuilder.Host is not supported. Use WebApplication.CreateBuilder(WebApplicationOptions) instead.
at Microsoft.AspNetCore.Builder.ConfigureHostBuilder.ConfigureHostConfiguration(Action1 configureDelegate) at Microsoft.Extensions.Hosting.HostingHostBuilderExtensions.UseContentRoot(IHostBuilder hostBuilder, String contentRoot) at Microsoft.Extensions.Hosting.WindowsServiceLifetimeHostBuilderExtensions.UseWindowsService(IHostBuilder hostBuilder, Action1 configure)
at Microsoft.Extensions.Hosting.WindowsServiceLifetimeHostBuilderExtensions.UseWindowsService(IHostBuilder hostBuilder)
at Program.$(String[] args) in C:\Users\Jonathan\source\repos\WebApplication5\WebApplication5\Program.cs:line 10
Steps to Recreate
Program.cs
My application is based on the ASP.NET Core Web API template. I followed instructions on https://learn.microsoft.com/en-us/aspnet/core/host-and-deploy/windows-service?view=aspnetcore-6.0&tabs=visual-studio#app-configuration and added UseWindowsService() to Program.cs
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Host.UseWindowsService();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
Deploy binary and create a service
I compile a binary with dotnet publish -c Debug --self-contained --runtime win-x64 -p:PublishSingleFile=true
Copy the output to the target machine and run in an Administrative Powershell
New-Service -Name WebApplication5 -BinaryPathName C:\Users\WDAGUtilityAccount\Desktop\webapp5\WebApplication5.exe
When I attempt to start the service:
PS C:> Start-Service WebApp5
Start-Service : Service 'WebApp5 (WebApp5)' cannot be started due to the following error: Cannot start service WebApp5 on computer '.'.
At line:1 char:1
+ Start-Service WebApp5
+ ~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : OpenError: (System.ServiceProcess.ServiceController:ServiceController) [Start-Service], ServiceCommandException
+ FullyQualifiedErrorId : CouldNotStartService,Microsoft.PowerShell.Commands.StartServiceCommand
When I use the Services GUI:
Windows could not start the WebApplication5 service on Local Computer
Error 1053:The service did not respond to the start or control request in a timely fashion.
Like the exception in event-viewer suggests, I needed to use a non-default constructor in Program.cs and set the ContentRootPath there.
Change this default constructor:
var builder = WebApplication.CreateBuilder(args);
Change to:
var webApplicationOptions = new WebApplicationOptions
{
ContentRootPath = AppContext.BaseDirectory,
Args = args,
};
var builder = WebApplication.CreateBuilder(webApplicationOptions);
Here's the rest of my program.cs for reference:
//set ContentRootPath so that builder.Host.UseWindowsService() doesn't crash when running as a service
var webApplicationOptions = new WebApplicationOptions
{
ContentRootPath = AppContext.BaseDirectory,
Args = args,
};
var builder = WebApplication.CreateBuilder(webApplicationOptions);
//All the following code is unchanged from my original program.cs
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Host.UseWindowsService();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
Works like a charm! Thanks.
one more line added to setup the url:
builder.WebHost.UseUrls("http://localhost:" + _portNo);

Swagger documentation does not update after deployment using Azure release pipeline

I am using Swashbuckle and swagger to document my .NET Core (3.1) API project.
The documentation is updated fine at the swagger endpoint, when I use the publish functionality in Visual Studio 2019 16.4.2.
However using the release pipeline in Azure does achieve the same.
Using swagger gen like this:
services.AddSwaggerGen(options =>
{
options.SwaggerDoc("v1", new OpenApiInfo
{
Title = "SqlViewService",
Version = "v1",
Description = "Alter views..."
});
});
I initially started adding the endpoint in the startup.cs class like this:
app.UseSwagger().UseSwaggerUI(s =>
{
s.SwaggerEndpoint("/swagger/v1/swagger.json", "SqlViewService v1");
});
And after searching a few articles and questions I have tried this:
app.UseSwagger().UseSwaggerUI(s =>
{
s.SwaggerEndpoint("/swagger/v1/swagger.json", "SqlViewService v1");
s.RoutePrefix = string.Empty;
});
And also this, adding current directory to the path:
app.UseSwagger().UseSwaggerUI(s =>
{
s.SwaggerEndpoint("./swagger/v1/swagger.json", "SqlViewService v1");
});
According to this article: https://learn.microsoft.com/en-us/aspnet/core/tutorials/getting-started-with-swashbuckle?view=aspnetcore-3.1&tabs=visual-studio
None of the tries have worked. Does anybody have a good suggestion or actual solution?
I had to add the following with in the Startup.cs class in the Configure method:
s.RoutePrefix = "swagger";
In this section:
app.UseSwagger().UseSwaggerUI(s =>
{
s.SwaggerEndpoint("/swagger/v1/swagger.json", "SqlViewService v1");
s.RoutePrefix = "swagger";
});
To solve page not found which suddenly started appearing.
Which prevented me from seeing whether the changes I made in my release pipeline was working, once that was solved.
The path to the folder used for deployment was:
And as my folder path for files to deploy was wrong I was basically deploying into a folder within old application files, so the release was never "picked up" by IIS.

ASP.NET Core set hosting environment in build process

I have an ASP.NET Core Api where I use the appsettings.{environmentname}.json configuration files. Then I also have the appropriate launchSettings.json file with the different environment options so I can run with any specific environment settings file.
In the Startup.cs, we have a conditional setting where if we are in a non-prod environment, then we use a specific set of Jwt authentication (just has some validating checks turned off), then in prod, we load a different version that has all of the checks to turn on.
On my localhost, this works great where environment.IsDevelopment() returns true, while environment.IsProduction() returns false. Great!
But, when I run this through our build process and deploy to our test environment, the environment.IsDevelopment() now returns false.
I have added in the option in the Program.cs file to add the ConfigurationBuilder so I can pass variables to my build process, which looks like this:
dotnet restore
dotnet build --environment "Development"
dotnet publish -o ..\Artifacts
I'll post the relevant files, and the associated code for more info...
Program.cs
public static IWebHost BuildWebHost(string[] args)
{
var config = new ConfigurationBuilder()
.AddCommandLine(args)
.Build();
return WebHost.CreateDefaultBuilder(args)
.UseConfiguration(config)
.UseStartup<Startup>()
.UseNLog()
.Build();
}
Startup.cs (ConfigureServices method)
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(options =>
{
// removed code not relevant...
// options.TokenValidationParameters = Environment.IsProduction()
// options.TokenValidationParameters = Environment.IsEnvironment("Prod")
options.TokenValidationParameters = Environment.IsDevelopment()
? devTokenValidationParameters
: prodTokenValidationParameters;
// options.TokenValidationParameters = devTokenValidationParameters;
});
Why are the helper environment.Is{EnvironmentName}() checks not working here?
The environment name is runtime concept rather than a compile (or build) time concept. This means that when building (or publishing) an application the environment is not yet known and setting is has no effect. Your code is not running when you publish the application.
You can control the environment name when running the application e.g. via an argument of dotnet run:
dotnet run --environment=Production
Or using a known environment variable ASPNETCORE_ENVIRONMENT. For example by executing this at the command line:
set ASPNETCORE_ENVIRONMENT=Production
This variable might also be set using the launchSettings.json file for debugging purposes. This file is generated when creating a new project using Visual Studio or dotnet new.
The default environment for an application is Production. Please refer to the documentation for more info about this topic.

Categories