I have this console application project where I use EF6 with postgresql, Quartz and Mass Transit and as DI I use Castle Winsdor. The goal of the project is to check periodically a folder (or folders) for new files and process them (mostly by storing data in the DataBase).
I wanted to use a logging service for debug purposes and I came across Serilog. I managed to add it to Quartz and EF, but I have issues adding it to Mass Transit.
What I've done so far:
I've added Serilog as Logging for Castle.Core.Logging
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Auto(Classes.FromThisAssembly());
var factory = container.Resolve<ILoggerFactory>();
container.AddFacility<LoggingFacility>(f => f.LogUsing(factory as SerilogFactory));
}
And then I added it to EF using a Logger Interceptor and to Quartz using Serilog settings.
But now I want to add it to my MassTransit Automatonymous, but I'm having trouble figuring it out.
First of all, I tried to add Serilog from the BusControl Configuration:
BusControl = Bus.Factory.CreateUsingInMemory(cfg =>
{
cfg.UseSerilog(Log.Logger); //Where `Log.Logger` is the Serilog Logger
});
But then I encountered a MassTransit.Logging.ILogger exception that was also discussed here.
In that thread I found that I should add Serilog (or any other logger) in a different way, by configuring the MassTransit LogContext like so
LogContext.ConfigureCurrentLogContext(loggerFactory);. But the thing is, they are now using
Microsoft.Extensions.Logging.Abstractions and I cannot convert my logger from Castle.Core.Logging.ILogger to Microsoft.Extensions.Logging.ILogger.
Is there any way to use my Castle.Core.Logging logger?
You need to use the Serilog.Extensions.Logging NuGet package, which adds ILoggerFactory support to Serilog. You can pass that interface to configure MassTransit via:
LogContext.ConfigureCurrentLogContext(loggerFactory);
MassTransit does not use any Castle facilities, however, there is a NuGet package for configuring MassTransit using ]Castle Windsor](https://masstransit-project.com/usage/containers/castlewindsor.html).
Update: You can view a sample Serilog configuration in this sample
Related
I have a .NET Core solution containing an API project that was targeting .NET Core 2.1, and I upgraded it to .NET Core 3.1. I've realized that there is a number of breaking changes from doing that, which I have gone through and modified to be compatible (such as converting UseMvc to UseRouting and so). But now I am stuck on one:
When I try to run the API project, I get this runtime error:
Some services are not able to be constructed (Error while validating
the service descriptor 'ServiceType:
Microsoft.Extensions.FileProviders.IFileProvider Lifetime: Singleton
ImplementationType:
Microsoft.Extensions.FileProviders.PhysicalFileProvider': No
constructor for type
'Microsoft.Extensions.FileProviders.PhysicalFileProvider' can be
instantiated using services from the service container and default
values.)
In Startup.cs, ConfigureServices, there is:
services.AddSingleton<IFileProvider, PhysicalFileProvider>();
which of course is the issue. But I'm not sure how do I convert this to be both compatible and have the API work the way it has been.
I did find an article on file providers that states:
The FileProviderSample sample app creates the provider in the
Startup.ConfigureServices method using
IHostEnvironment.ContentRootFileProvider:
var physicalProvider = _env.ContentRootFileProvider;
But it's not clear as to exactly where within ConfigureServices that is supposed to go... or if that replaces the AddSingleton... or how that's going to affect the API's behavior. So I'm not sure what to do with this.
How would DI create an instance of PhysicalFileProvider without specifying a root directory?
You could create an instance by yourself specifying the root, then registering that instance into the services collection.
This works for me:
public void ConfigureServices(IServiceCollection services) {
// (...)
IFileProvider fp = new PhysicalFileProvider("C:\\path\\to\\by\\root");
// or, you could get the file provider from the environment:
// IFileProvider fp = _env.ContentRootFileProvider;
services.AddSingleton<IFileProvider, PhysicalFileProvider>(_ => fp);
// (...)
}
Then, I just inject it into my DI managed class:
IFileProvider _fileProvider;
public FilesController(IFileProvider fp) {
this._fileProvider = fp;
}
As an alternative, and If you don't mind changing the constructor parameters of your class, you could inject IWebHostEnvironment instead. Then you could have easy access to the file provider from environment.
When adding AWS Services to Services Collection in .NET Core, should I go with the default which well add as a Singleton or should I use the override to set as Transient?
For reference, displaying default option (Singleton) for DynamoDB and Transient for SQS:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddDefaultAWSOptions(Configuration.GetAWSOptions());
services.AddHttpContextAccessor();
// Add AWS Services
services.AddDefaultAWSOptions(Configuration.GetAWSOptions());
services.AddAWSService<IAmazonDynamoDB>();
services.AddAWSService<IAmazonSQS>(lifetime: ServiceLifetime.Transient);
}
I've seen many examples go with the default, but reading the is article suggests going with Transient unless there is a reason to go with Singleton:
https://dotnetcoretutorials.com/2017/03/25/net-core-dependency-injection-lifetimes-explained/#comments
From a dev of the AWS SDK I recommend leaving it at the default. The AWS service clients added to the collection are thread safe. We added the overload to set the service lifetime to provide flexibility in case somebody is doing some really unusual.
I have some services that were initially designed to be called from my ASP.NET Core 2.1 web application. They have dependencies injected to their constructors using Microsoft.Extensions.DependencyInjection package stuff. Some of them have a dependency of ILogger logger.
public GroupService(ILogger<GroupService> logger)
{
...
}
I am building a service provider within the function so that they can still work as expected however I'm wondering what I should do about the logger dependencies. An Azure Function (V2) gets an ILogger injected into it by default but that can't be used in the DI container to create the additional loggers that the services require.
Is there a LoggerFactory registered somewhere "under the covers" that I can get access to to be used in my DI container? I think that would allow me to add additional loggers that log to the functions output window or am I completely misunderstanding how logging in a function would work?
Do I just need to set up a new LoggerFactory and make that log to the ApplicationInsights instance used by the functions project?
Using the most recent Azure Function runtime, you can now have the runtime inject your dependencies through constructors.
You can now remove the static keywords from your Azure Function and have the runtime.
Here is how you can set this up:
[assembly: WebJobsStartup(typeof(StartUp))]
public class StartUp : IWebJobsStartup
{
public void Configure(IWebJobsBuilder webJobsBuilder)
{
// Enables logging and sets the minimum level of logs.
webJobsBuilder.Services.AddLogging(loggingBuilder =>
{
loggingBuilder.SetMinimumLevel(LogLevel.Debug);
});
// Registers your services.
webJobsBuilder.Services.AddTransient<IGroupService, GroupService>();
}
}
In my project I use Serilog and ASP.Net Core. The initialization part looks like that:
var provider = services.BuildServiceProvider();
var logFactory = provider.GetRequiredService<ILoggerFactory>();
logFactory.AddSerilog().AddConsole();
return provider;
This will add Serilog to the logging pipeline.
I want to add to the logger an ability to say whether there was logs with type 'Warning' or not in order to make some result message. For example it could be a method that returns simple bool saying about that.
How should I do it in a correct way? Can I somehow override current Core behavior by changing the way the logger handles 'Warning' logs in order to save somewhere the fact that LogWarning method has been called? Or should I implement my own logger (ILogger) as well as ILoggerFactory and ILoggerProvider with needed functionality? But then how can I save Serilog part in that scenario?
I want to information to the log in my web app. Seems like it would fall under the Information category. The problem is that if I set the default logging level to Information, the .NET Core itself will write stuff to the log file that I don't want there.
I have the following:
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Is(logLevel)
.WriteTo.RollingFile(Path.Combine(env.ContentRootPath, "{Date}.txt"))
.CreateLogger();
Is it possible to create a logger where I only write my own events to. This applies to any .net core compatible logging frameworks out there.
Or do I need to roll my own custom class for this?