I know you can set NLog's internal log file programmatically like this:
NLog.Common.InternalLogger.LogFile = #"C:\Logs\nlog.log";
The above trick does not work for the following scenario, where I need to be able to set internal log file that's used by injected NLog. The one that gets created inside ASP.NET Core WebApi, using the following
.ConfigureLogging(logging =>
{
logging.SetMinimumLevel(LogLevel.Trace);
})
.UseNLog();
Are there any workarounds for me to programmatically configure LogFile and LogLeve of the NLog object that gets dependency injected?
Why not just remove internalLogFile="..." from NLog.{ASP_NET_CORE_ENVIRONMENT}.config ?
Or just re-assign InternalLogger.LogFile after having called LogManager.Setup().LoadConfigurationFromAppSettings() ?
Related
MAUI has dependency injection setup similar to what ASP.NET Core has in the Startup.cs class. This one is set in MauiProgram.cs file by default.
My question is: How can I get a service instance in this file after services registration? I guess, one solution will be the following, but then I must edit this code also if the constrctors of these services change during time:
var keyValueStore = new PreferencesKeyValueStore();
var accountService = new AccountService(keyValueStore);
var profileService = new ProfileService(keyValueStore);
builder.Services.AddSingleton<IKeyValueStore>(keyValueStore);
builder.Services.AddSingleton<IAccountService>(accountService);
builder.Services.AddSingleton<IProfileService>(profileService);
//Here now I can use accountService and profileService to do something
I can not find more elegant solution that will return the service instance for me from the DI container. Something like:
builder.Services.AddSingleton<IKeyValueStore, PreferencesKeyValueStore>();
builder.Services.AddSingleton<IAccountService, AccountService>;
builder.Services.AddSingleton<IProfileService, ProfileService>();
//Now I can't perform something like: var accountService = diContainer.GetInstance<IAccountService>(); or similar.
I don't know how to reach di container and ask it to provide me registered instance.
Actually, the documentation provided a simple way to do so.
Check it here
They recommended to use the Handler property of any object of type Element, there you can write the code :
// Considering you want to resolve a service from your custom interface IMyService
var service = this.Handler.MauiContext.Services.GetService<IMyService>();
// Then you can use the resolved service..
But there are some issues, personally it never worked for me, the Handler property may be null because of the lifecycle of the Element you are calling it on.
To avoid this issue, use a full line like:
var service = Application.Current.MainPage
.Handler
.MauiContext
.Services
.GetService<IMyService>();
// Then you can use the resolved service..
This works fine for me
Hope it helps you ..
Application is not able to talk to AWS Parameter Store in .NET 6.
It is always talking to appsettings.json.
I tried debugging locally, still same behavior. Not able to find the SystemManagerConfiguration under list of configuration .
var builder = WebApplication.CreateBuilder();
var connectionString = builder.Configuration.GetConnectionString("OrderTrackerDatabase");
Packages Used
Library Source Code : https://github.com/aws/aws-dotnet-extensions-configuration
image
I got the same issue and finally resolved it.
The samples code in https://github.com/aws/aws-dotnet-extensions-configuration missed one line as below after called "AddSystemsManager" method in .Net 6.
builder.Services.Configure<Settings>(builder.Configuration.GetSection($"common:settings"));
After added above line, then I'm able to get the correct values from AWS Parameter Store when using the settings.
I've also created an issue of this in GitHub as below -
https://github.com/aws/aws-dotnet-extensions-configuration/issues/114
I believe the problem might be the trailing slash after "/OrderTracking/", try "/OrderTracking" instead.
WebApplication.CreateBuilder() will create new instance and doesn't carry over the SystemManager configuration.
Instead, use IConfiguration instance through constructor DI.
var connectionString = _configuration.GetConnectionString("OrderTrackerDatabase");
In my case this extensions method was returning null at my lambda:
private static IConfiguration InitializeConfiguration() => new ConfigurationBuilder()
.AddSystemsManager($"/my-data", true, TimeSpan.FromMinutes(5))
.Build();
Because the role of lambda didn't have permission for read SSM for that resource.
User: is not authorized to perform: ssm:GetParametersByPath on resource
So, just add necessary permission (ssm:GetParametersByPath) for the role of lambda to your resource at System Manager.
In my case, I am using lambda serverless, so the IConfig is always null when it is passed to the controller.
I resolved it by changing the IOptions<Settings> settings in the Controller constructor to IConfiguration settings and then access the parameters by name like _settings.GetValue<string>("ParameterName")
A little less "Object Oriented", but it seemed much easier than this complex solution
I am using the options pattern inside of my application, reading properties from my appsettings.json file and using them in classes throughout my application.
However, I have a case where I need to use these properties inside of my program.cs file itself. Here is code which does not work since I am not able to inject an instance of the config within the program.cs file. The code shows what I would like to happen... is there a better way of doing this and still staying within the options pattern?
builder.Services.Configure<SwaggerConfig>(builder.Configuration.GetSection("Swagger"));
var app = builder.Build();
app.UseSwagger();
app.UseSwaggerUI(s =>
{
s.SwaggerEndpoint( SwaggerConfig.Url ,
SwaggerConfig.Name);
s.RoutePrefix = SwaggerConfig.RoutePrefix;
});
You have access to the IServiceProvider within your code. You can obtain the configuration you are looking for with app.Services.GetRequiredService<IOptions<SwaggerConfig>>().Value.
The thing is, once you call builder.Build(), the DI container will be also built.
I'm trying to configure my services for an ASP.NET Core 2.0 app/website.
I wish to reference some key/values from my appsettings.json file, in this method.
I'm not sure if what I'm going is OK or not:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvcCore()
.AddJsonFormatters()
.AddCors();
var applicationSettings = Configuration.GetSection("Settings").Get<ApplicationSettings>();
services.AddSingleton(applicationSettings);
// ** THIS IS WHAT I ORIGINALLY HAD, BUT IT'S ONLY SETTING
// THE VALUE IN DI/IOC.
//services.Configure<ApplicationSettings>(options => Configuration.GetSection("Settings")
// .Bind(options));
var foo = new Foo(applicationSettings.SomeSetting);
services.AddSingleton(foo);
}
See how i'm manually adding a singleton and then later, referring a value from the app settings instance?
vs
just configuring ...
So, is either way OK or is there a specific reason for either/or?
Remember -> i'm going to need to inject my settings into controllers, etc...
Technically, you can do either. In both cases, you have the configuration registered and available through dependency injection, so everything can depend on it and will get the configuration instance.
You are also using the centrally set up Configuration there, so you have all the benefits from the configuration stack there, e.g. multiple providers or environment specific overrides.
However, the favor has definitely moved to the IOptions way of consuming custom configuration. It’s the “state of the art” and used throughout ASP.NET Core for literally everything. It also allows you to switch to options that can be updated at runtime. That’s very powerful and might become useful eventually (not necessarily for your specific situation with the singleton, but maybe for something else).
It’s also really easy to set this up, actually shorter than what you tried:
services.Configure<ApplicationSettings>(Configuration.GetSection("Settings"));
services.AddSingleton<Foo>();
Note that, even for singletons, you shouldn’t explicitly create a new instance of it, but let DI handle that. If your class has the correct constructor, dependencies will be automatically injected anyway:
public class Foo
{
private readonly ApplicationSettings _settings;
public Foo (IOptions<ApplicationSettings> settings)
{
_settings = settings.Value;
}
}
Of course, Foo can also have more dependencies here. Since it’s going to be constructed by DI, you can just add more dependencies in the constructor, without having to update some new call somewhere.
If you need to configure certain services with settings that depend on your configuration, you still should not bind your configuration there directly. All of configuration is DI-based, so you just need to inject the right thing; a IConfigureOptions<T>. That’s basically the thing that provides the IOptions<T> to services later. In your JWT case, this could look like this:
// instead of passing an option configuration delegate here…
services.AddAuthentication().AddJwtBearer();
// … we register a IConfigureOptions<JwtBearerOptions> instead
services.AddSingleton<IConfigureOptions<JwtBearerOptions>, ConfigureJwtBearerOptions>();
// … ConfigureJwtBearerOptions could look like this:
class ConfigureJwtBearerOptions : IConfigureOptions<JwtBearerOptions>
{
private readonly ApplicationSettings _settings;
public ConfigureJwtBearerOptions(IOptions<ApplicationSettings> settings)
{
_settings = settings.Value;
}
public void Configure(JwtBearerOptions options)
{
// configure JwtBearerOptions here, and use your ApplicationSettings
options.MetadataAddress = _settings.JwtMetadataAddress;
}
}
This might seem unnecessarily verbose compared to just passing a delegate to AddJwtBearer() but note that this is exactly what happens under the hood when you pass that delegate: An IConfigureOptions<JwtBearerOptions> object will be created that calls your delegate in the Configure() call. So this is really just the same.
Note that for authentication schemes, you might actually set up a IConfigureNamedOptions<T> instead, which is almost the same thing except it can configure the options based on a name. For authentication schemes, that is the scheme name, so basically you check the scheme name in Configure() and then decide how to configure your options.
As for creating singleton instances, especially expensive ones, I would argue that ConfigureServices is the wrong place for such a thing. ConfigureServices is called very early in the application startup phase, when the whole DI infrastructure does not exist yet. So you could not rely on anything when creating your instance. I would also argue that it is still not your job to create the object but you should DI handle the creation of it and as such give it also control over its lifecycle.
If you absolutely need to control when the instance is created, I would suggest you to use the lifecycle events for this: Basically, after the application has set up properly but before a first request comes in, you request the instance of your services and initialize it. That way, you can still have it fully depend on DI, and it won’t be created lazily with the first request.
You can register lifecycle handlers in the Configure method:
public void Configure(IApplicationBuilder app, IApplicationLifetime applicationLifetime)
{
applicationLifetime.ApplicationStarted.Register(() =>
{
// application has started, request the singleton here to trigger DI to
// create the instance
app.ApplicationServices.GetService<ExpensiveSingleton>();
});
// …
}
}
Well the problem with that approach is that it will be impossible to load multiple configuration sections through DI. The Configuration API has many features, such as pluggable configuration provides, snapshots, etc.
I would suggest you at least use a class to bind you configuration section against, so DI can inject it based on its type. If you further down the line have need to another configuration class you won't run into issues.
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/configuration
I can't find a way how to migrate the application from aspnet core 1.1 to 2.0 which is using cookie authentication.
Most useful resources I already know are:
https://learn.microsoft.com/en-us/aspnet/core/migration/1x-to-2x/identity-2x#cookie-based-authentication
https://github.com/aspnet/announcements/issues/262
https://github.com/aspnet/Home/issues/2128 (my own question)
Unfortunately, I am still stuck. Here is how I do it:
In Startup.cs ConfigureServices(IServiceCollection services)I have:
services.AddSingleton<IConfigureNamedOptions<CookieAuthenticationOptions>, CookieAuthenticationOptionsSetup>();
and later:
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie();
The CookieAuthenticationOptionsSetup class implements IConfigureNamedOptions and sets options.Cookie.Name = "test" inside the Configure method.
I event tried to manually create and set Name property to "Cookies".
If I try to change the name of cookie with lambda expression inside Startup.cs AddCookie method, it works as expected. But if I don't, the CookieAuthenticationOptionsSetup is never used and the default cookie name (.AspNetCore.Cookies) is used.
What I am missing?
AddCookie() by default calls AuthenticationBuilder.AddScheme. From there, we can learn how the options would be ideally registered if you passed them to the AddCookie call:
Services.Configure(authenticationScheme, configureOptions);
So let’s take a look at how Services.Configure works with named options. What ultimately gets registered on the service collection are IConfigureOptions<CookieAuthenticationOptions>>.
So I would guess that is the exact type that is being looked up later when the options are resolved via DI. And in fact, that is the exact type that is being request by the OptionsFactory that is being used by the OptionsMonitor which is requested by the authentication handler.
So, tl;dr: You are registering your custom configuration as the wrong type. You should register it as an IConfigureOptions<>:
services.AddSingleton<IConfigureOptions<CookieAuthenticationOptions>, CookieAuthenticationOptionsSetup>();
Note of course that your CookieAuthenticationOptionsSetup needs to implement IConfigureNamedOptions properly and respond to a Configure call with your scheme name (CookieAuthenticationDefaults.AuthenticationScheme).
In addition to this answer, I also had to add Name property to the class which implements IConfigureNamedOptions<T> and set it in public void Configure(string name, CookieAuthenticationOptions options) method.
Few additional notes for those who will have the same problem:
To apply Authorize attribute globally, authentication scheme must be added (worked without it previously):
services.AddMvcCore(a =>
{
var policy = new AuthorizationPolicyBuilder().AddAuthenticationSchemes(CookieAuthenticationDefaults.AuthenticationScheme).RequireAuthenticatedUser().Build();
a.Filters.Add(new AuthorizeFilter(policy));
});
To use IsAuthenticated property inside middleware, app.UseAuthentication() must be called before registering the middleware.
It is not exactly clear what is the question...
But if you want just to set cookie name (or other options) and really do not need to implement IConfigureNamedOptions try something like this:
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie(options =>
{
options.Cookie.Name = "TestName";
}