ASP Core .NET 6 works when I run it manually, but it fails when I install as windows service - asp.net-core

I have an ASP Core .NET 6 application that I want to install as windows services.
I am using minimal API and this is the code:
using Microsoft.AspNetCore.ResponseCompression;
using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Hosting.WindowsServices;
using System.IO.Compression;
using System.Security.Cryptography.X509Certificates;
using GestorOrdenadores.Service.Server.Grpc;
using Serilog;
using Microsoft.Extensions.Configuration;
using Serilog.Events;
File.AppendAllText("LogManual.txt", DateTime.Now + ": Iniciado");
Log.Logger = new LoggerConfiguration()
.WriteTo.Console()
.CreateBootstrapLogger();
Log.Information("Starting up");
try
{
WebApplicationOptions options = new WebApplicationOptions
{
Args = args,
ContentRootPath = WindowsServiceHelpers.IsWindowsService() ? AppContext.BaseDirectory : default
};
WebApplicationBuilder builder = WebApplication.CreateBuilder(options);
builder.Host.UseSerilog((ctx, lc) => lc
.WriteTo.Console()
.ReadFrom.Configuration(ctx.Configuration));
builder.WebHost.ConfigureKestrel((context, options) =>
{
string miStrCertificado = File.ReadAllText("certificados/server.crt");
string miStrKey = File.ReadAllText("certificados/server.key");
X509Certificate2 miCertficadoX509 = X509Certificate2.CreateFromPem(miStrCertificado, miStrKey);
X509Certificate2 miCertificado2 = new X509Certificate2(miCertficadoX509.Export(X509ContentType.Pkcs12));
miCertficadoX509.Dispose();
options.ListenAnyIP(5001, listenOptions =>
{
listenOptions.Protocols = HttpProtocols.Http1AndHttp2;
listenOptions.UseHttps(miCertificado2);
});
});
builder.Services.AddGrpc();
builder.Host.UseWindowsService();
WebApplication app = builder.Build();
app.UseSerilogRequestLogging();
app.MapGrpcService<GestorOrdenadoresService>();
app.MapGet("/", () => "Communication with gRPC endpoints must be made through a gRPC client. To learn how to create a client, visit: https://go.microsoft.com/fwlink/?linkid=2086909");
await app.RunAsync();
}
catch(Exception ex)
{
File.AppendAllText("LogManual.txt", DateTime.Now + ": EXCEPTION: " + ex.Message);
Log.Fatal(ex, "Unhandled exception");
}
finally
{
File.AppendAllText("LogManual.txt", DateTime.Now + ": Finally");
Log.Information("Shut down complete");
Log.CloseAndFlush();
}
When I debug or run the application manually, it creates the log, but when I install the service and try to run it, in the service manager of windows, when I click to start, I get the error 1067.
If I go to the event viewer of windows, I get the error with ID 7034.
And in this case no log files are created.
How the application can run when I run it manually, I guess the problem is how I try to set the service part of the code, but I don't know how could be the problem.

Win32 services run in %WinDir%\System32 by default (as I describe on my blog), and I'd be surprised if you could just write out a LogManual.txt in that folder. So, you're probably getting an exception, which is causing your service to fail to start.
A lot of services find this inconvenient, and change their working directory on startup:
Environment.CurrentDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);

Related

Net6 / NetCore - Restart the application process

We are writing an SDK for our company where the SDK starts all application secrets independently the Hosting environment. (Azure/AWS/Openshift/IIS/etc...)
If the SDK startup fails then the process should be "restarted" in order that the next request should start all over again as it was the first request.
ej:
using Microsoft.Web.Administration;
using MySDK.Core;
using MySDK.SEC;
using MySDK.SEC.Model;
var builder = WebApplication.CreateBuilder(args);
using var loggerFactory = LoggerFactory.Create(loggingBuilder => loggingBuilder
.SetMinimumLevel(LogLevel.Trace)
.AddConsole());
ILogger logger = loggerFactory.CreateLogger("Startup Initializer");
builder
.Services
.AddMySDK(builder.Configuration)
.AddSEC(
builder.Configuration,
logger: logger,
options: new MySDK.SEC.Model.SecOptions() {
Services = builder.Services,
OnInitError = (object sender, MySDK.SEC.Events.ErrorEventArgs e) => {
//- Here we need to stop the requests.
//- The next request should start all over again from the begining "var builder = WebApplication.CreateBuilder(args);"
},
OnUpdateSecret = (object sender, MySDK.SEC.Events.UpdateSecretsEventArgs e) => {
//- Here we need to be able to do 2 things.
//- 1- Call the SEC updater and update all the secrets for the app.
//- 2- Restart the app so the next request starts all over again from the begining "var builder = WebApplication.CreateBuilder(args);".
}
}
);
//-- Start all DBContext using SDK configuration
//-- Init AzureAD using SDK configuration
//-- Init other components using SDK configuration
// Add services to the container.
builder.Services.AddControllersWithViews();
var app = builder.Build();
...
...
...
app.Run();
We tried several codes all around ending and none worked.
Thanks,

Puppeteer sharp in Blazor page Failed to create connection

I created a project in blazor using Visual Studio 2022 and dot net 6.0.
He added the PuppeteerSharp package and created a small test function:
try
{
using (var myBr = new BrowserFetcher())
{
await myBr.DownloadAsync(BrowserFetcher.DefaultChromiumRevision);
var launchOptions = new LaunchOptions { Headless = true };
_browserPuppeter = await Puppeteer.LaunchAsync(launchOptions);
_pagePuppeteer = await _browserPuppeter.NewPageAsync();
await _pagePuppeteer.GoToAsync(url);
}
}
catch (Exception exc)
{
errore = exc.Message + DateTime.Now.ToString(" HH:MM:ss.zzz");
}
When I run it from visual studio locally it loads the page correctly. When I publish on a website in Web Hosting (https://www.webwiz.net) two things happen:
fails to download chromium.
If I upload the directory .local-chromium via ftp, it gives me the error:
"Failed to create connection"
Any idea?

Migration to Minimal API - Test Settings Json not overriding Program

Thanks to this answer: Integration test and hosting ASP.NET Core 6.0 without Startup class
I have been able to perform integration tests with API.
WebApplicationFactory<Program>? app = new WebApplicationFactory<Program>()
.WithWebHostBuilder(builder =>
{
builder.ConfigureServices(services =>
{
});
});
HttpClient? client = app.CreateClient();
This has worked using the appsettings.json from the API project. Am now trying to use integrationtestsettings.json instead using:
IConfiguration configuration = new ConfigurationBuilder()
.SetBasePath(ProjectDirectoryLocator.GetProjectDirectory())
.AddJsonFile("integrationtestsettings.json")
.Build();
WebApplicationFactory<Program>? app = new WebApplicationFactory<Program>()
.WithWebHostBuilder(builder =>
{
builder.ConfigureAppConfiguration(cfg => cfg.AddConfiguration(configuration));
builder.ConfigureServices(services =>
{
});
});
_httpClient = app.CreateClient();
I have inspected the configuration variable and can see the properties loaded from my integrartiontestsettings.json file. However, the host is still running using the appsettings.json from the server project.
Previously, in .Net5, I was using WebHostBuilder and the settings were overridden by test settings.
WebHostBuilder webHostBuilder = new();
webHostBuilder.UseStartup<Startup>();
webHostBuilder.ConfigureAppConfiguration(cfg => cfg.AddConfiguration(_configuration));
But cannot get the test settings to apply using the WebApplicationFactory.
It seems the method has changed.
Changing:
builder.ConfigureAppConfiguration(cfg => cfg.AddConfiguration(configuration));
To:
builder.UseConfiguraton(configuration);
has done the trick.
builder.ConfigureAppConfiguration, now it's configuring the app (after your WebApplicationBuilder.Build() is called) and your WebApplication is created.
You need to "inject" your configurations before the .Build() is done. This is why you need to call UseConfiguraton instead of ConfigureAppConfiguration.

Call Azure API from WebJob/ Shared code between WebJob and web api

I have a web api in an ASE and an associated web job. I am trying to call this web api from the web job but it always fails with winhttpexception: a security error has occurred. I have put in all the tls related settings but still getting the error.
Any suggestions on the error?
Also is there a way to share code between WebJob and web api?
I was able to resolve the issue by setting the below in my code.This resolved the Security Error.
using(var handler = new HttpClientHandler
{
ServerCertificateCustomValidationCallback = (sender,certificate,chain,sslPolicyErrors) => true
})
You could create a console app and publish it as Azure WebJobs. For username and password you could click Get Publish Profile in your Azure webapp overview to get them.
Then you could use the following code in Console App to call your Azure Webapi.
string userName = "$xxxxxx";
string userPassword = "xxxxxxxxxxxxx";
string webAppName = "xxxxxx";
var base64Auth = Convert.ToBase64String(Encoding.Default.GetBytes($"{userName}:{userPassword}"));
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("Authorization", "Basic " + base64Auth);
var baseUrl = new Uri($"https://{webAppName}.azurewebsites.net/api/values");
var result = client.GetAsync(baseUrl).Result;
if (result.IsSuccessStatusCode)
{
var readTask = result.Content.ReadAsStringAsync();
readTask.Wait();
var value = readTask.Result;
Console.WriteLine(value.ToString());
}
}
Console.WriteLine("run successfully");
Output as below:

Azure WebJobs useTimers method not available in .net core 2.0

I am using Microsoft.azure.webjobs (3.0.0-beta1-10941) in a .net core 2 console app. The aim is to create a azure web job,
var config = new JobHostConfiguration();
if (config.IsDevelopment)
{
config.UseDevelopmentSettings();
}
config.UseTimers();
var host = new JobHost(config);
host.RunAndBlock();
The config.UseTimer() is expected a reference of Microsoft.Azure.WebHost.Host but it needs 2.1.0.0. If i add this by removed beta version 3.0.0-beta1-10941 then host.runandblock() falls over at WindowsAzure.Storage incorrectly deployed install edm, data, or data.services.
I installed the dependencies but still no luck
I have downgraded windowsAzure.Storage to lower than 9 but same issue.
Azure WebJobs NuGet Package Error
Any ideas how to resolved config.UseTimes() in .net core 2.0?
Thanks
Any ideas how to resolved config.UseTimes() in .net core 2.0?
In your case you could use the Microsoft.Azure.WebJobs.Extensions Version 3.0.0-beta4.
I also do a demo for it. The following is detail steps.
1.Create a net core 2.0 console application.
2.Add the following code in the Program.cs file.
var config = new JobHostConfiguration();
if (config.IsDevelopment)
{
config.UseDevelopmentSettings();
}
config.UseTimers();
config.DashboardConnectionString ="storage connectionstring";
config.StorageConnectionString = "storage connectionstring";
var host = new JobHost(config);
host.RunAndBlock();
3. Add the Functions.cs file to the project.
public class Functions
{
public static void CronJob([TimerTrigger("0 */1 * * * *")] TimerInfo timer)
{
Console.WriteLine("Cron job fired!");
}
}
4. Test it on my side.
Check documentation. There are solutions for 2.x and 3.x.
For 3.x can be used "b.AddTimers();" Example:
static async Task Main()
{
var builder = new HostBuilder();
builder.UseEnvironment(EnvironmentName.Development);
builder.ConfigureLogging((context, b) =>
{
b.AddConsole();
});
builder.ConfigureWebJobs(b =>
{
b.AddAzureStorageCoreServices();
b.AddAzureStorage();
b.AddTimers();
});
var host = builder.Build();
using (host)
{
await host.RunAsync();
}
}
The time-triggered method: (need to be in a static class)
public static class TimeTrigger
{
// Runs once every 10 seconds
public static void TimerJob([TimerTrigger("00:00:10")] TimerInfo timer)
{
Console.WriteLine("Timer job fired!");
}
}