nested DependencyInjection in ConfigureServices() of ASP.NET CORE - asp.net-core

I realize DI (ctor based) in .NET CORE is quite straight forward but if it comes to nested injections I struggle.
This is quite simple:
public void ConfigureServices(IServiceCollection services)
{
services.AddRavenDbDocStore(x => x.AfterInitializeDocStore = RavenConfiguration.AfterInitializeDocStore());
services.AddRavenDbAsyncSession();
services.AddSingleton(new ExceptionHelper());
services.AddScoped<ICompoundService>(x => new CompoundService(x.GetService<IAsyncDocumentSession>(), x.GetService<ExceptionHelper>()));
But whenever I need to register a type within e.g a lamba of another registration, I have problems resolving dependencies:
services.AddMvc(setup =>
{
ILogger logger; // how would I get that?
setup.Filters.Add(new ApiExceptionFilter(logger));
}).AddFluentValidation();
Is there a good way to deal with that?
I certainly do not want to call this in ConfigureServices
var sp = services.BuildServiceProvider();
I read about this in Resolving instances with ASP.NET Core DI from within ConfigureServices
but I do not reall see an elegant option here...
Update:
After reading comments I realized that you can register Filters per type:
setup.Filters.Add<ApiExceptionFilter>()
Then you would not have to pass dependencies in the first place.
Still I wonder if there is a best practice for similar scenarios where you cannot access ServiceProvider in the lambda.

Related

ILogger in Asp.net Core and Serilog

I have a question,
Is there any concern if I use ILogger in Serilog on behalf of Microsoft logger?
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton(Log.Logger);
}
Then use from ILogger in Serilog namespace.
_logger.Error(exception, "Error", exception.Message, exceptionId);
What is your idea?
Microsoft.Extensions.ILogger is an abstraction that decouples your application code (the code that writes log entries) from the underlying logging framework.
Using this abstraction brings the benefit, that you could easily change the Logging Framework underneath (e.g. replace Serilog with NLog) and don't have to update all references in your application code.
Also using Microsoft's abstractions also allows you to configure logging of your application code and logging of Microsoft SDKs you might use at a single place.
The downside of abstractions is that you have to aggree to a common minimum interface provided by all logging frameworks. It's not so easy to use Framework-Specific features this way.
So most of the time i would advise using the abstraction.
If you have very specific features from Serilog you would like to interact with you could think about using ILogger from Serilog directly.
However you can configure serilog in the provider registration as well to a high degree and probably get the best of both worlds.
You would configure Serilog factory interface to be used instead of built-in Logger factory for creating ILogger
First in program.cs, add the Serilog ILoggerFactory to your IHostBuilder with UserSerilog() method in CreateHostBuilder():
public static IHostBuilder CreateHostBuilder(string[] args) =>
new HostBuilder()
.ConfigureHostConfiguration(builder => { /* Host configuration */ })
.ConfigureAppConfiguration(builder => { /* App configuration */ })
.ConfigureServices(services => { /* Service configuration */})
.UseSerilog(); // <- Add this line
}
How the library works behind the scenes
On the face of it, completely replacing the default ASP.NET Core logging system to use a different one seems like a big deal. Luckily, thanks to the use of interfaces, loose coupling, and dependency injection, the code is remarkably simple! The whole extension method we used previously is shown below:
public static class SerilogHostBuilderExtensions
{
public static IHostBuilder UseSerilog(this IHostBuilder builder,
Serilog.ILogger logger = null, bool dispose = false)
{
builder.ConfigureServices((context, collection) =>
collection.AddSingleton<ILoggerFactory>(services => new
SerilogLoggerFactory(logger, dispose)));
return builder;
}
}
The UseSerilog() extension calls the ConfigureServices method on the IHostBuilder and adds an instance of the SerilogLoggerFactory as the application's ILoggerFactory. Whenever an ILoggerFactory is required by the app (to create an ILogger), the SerilogLoggerFactory will be used.
for more Information check this Link
"The downside of abstractions is that you have to aggree to a common minimum interface provided by all logging frameworks. It's not so easy to use Framework-Specific features this way."
I think we can always create extension methods to overcome this downside.

How to properly call a method at startup in Asp .Net Core?

I would like to reuse a library class that I made for some projects in Asp .Net Framework within an Asp .Net Core project on which I am now working.
For that project I have to use a MySQL database so I added the MySqlConnector NuGet package to my library class.
As the registered .NET Data Providers are not automatically added to the Global Assembly Cache I must register it manually thanks the call of that method DbProviderFactories.RegisterFactory("MySqlConnector", MySqlClientFactory.Instance) during application startup as mentionned here.
It's my first .Net core project so I don't know if that's how I should do it but I called that method in the Startup.cs file like this :
It is working but I am wondering if it's the right way to do it. Would you advise me another proper way to do it?
Thanks
There is nothing fundamentally wrong with your approach, IMO.
One problem I see is the task you're trying to run takes too long, in which case you're better off spawning a task.
The other is reusability, your code is coupled together. You could solve that by wrapping it in a class and injecting it into a middleware component by interface, and then calling a method. For example:
public interface ITask { void Run(); }
class RegisterMySqlTask : ITask { public void Run() { DbProviderFactories.RegisterFactory("MySqlConnector", MySqlClientFactory.Instance); } }
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<ITask, RegisterMySqlTask>();
//rest goes here
}
public void Configure(IApplicationBuilder app)
{
app.Use(async (context, next) =>
{
context.RequestServices.GetRequiredService<ITask>().Run();
await next(context);
});
//rest goes here
}
Note, however, that this may be overcomplicating things. As I said, I believe that you are not doing anything wrong.

.NET Core DI passing info of AddHttpContextAccessor to a service

In my solution I have projects for my API, my Web App and also have another project which includes services, that are getting some information from a database and formatting them, these are currently only used by this API, but these could be used by other API projects in the future.
My API have a couple controllers that are returning JSON data from the result returned by the services.
In some cases the services needs to call the API to process some information before calling the request to the database. Since I have dev/staging/prod environment with their own URL I don't want to hardcode the URLs in the services I want to use DI to get these dynamicaly depending on the context.
In the Startup.cs of my API I have added services.AddHttpContextAccessor(); in the ConfigureServices(IServiceCollection services) section to gain access to the current http context :
public void ConfigureServices(IServiceCollection services)
{
...
services.AddHttpContextAccessor();
...
}
With that I know I can now access the information directly into my controller which I tried and it worked :
public class DataController : ControllerBase
{
...
private readonly string _baseUrl;
public FeaturesController(...
,IHttpContextAccessor httpContextAccessor)
{
...
_baseUrl = UrlHelpers.ShowBaseURL(httpContextAccessor) ?? throw new ArgumentNullException(nameof(_baseUrl));
}
}
public static class UrlHelpers
{
public static string ShowBaseURL(IHttpContextAccessor httpcontextaccessor)
{
var request = httpcontextaccessor.HttpContext.Request;
var absoluteUri = string.Concat(
request.Scheme,
"://",
request.Host.ToUriComponent(),
request.PathBase.ToUriComponent());
return absoluteUri;
}
}
I could do just about the same thing in the services but to me they should not act directly on the httpcontext, since this is not the job they are meant to do. I am sure I could do better by adding a class injected of some sort that would have then make the specific value available to my services.
I know I could also pass the _baseUrl directly as an argument when calling the services from my controller but since I am trying to better understand DI and use it I would rather find another way if it is viable.
I can't give credit but I went with Steven solution which make the most sens

How to implement the IConfiguration interface in ASP.NET Core for Dapper usage?

I am familiar with using ASP.NET Core with EF Core, where you just define your DBContext in the ConfigureServices method from Startup.cs for DI, like so:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.AddDbContext<MyDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
}
However, I have been asked to add Dapper to this project (it will still use EF) but I can't even fetch the connection string. I found Brad Patton's answer here to be along the lines of what I had in mind, but he leaves the setup of the Configuration object up to the reader:
public void ConfigureServices(IServiceCollection services)
{
...
// Add the whole configuration object here.
services.AddSingleton<IConfiguration>(Configuration);
}
After googling around for a couple of hours, I still have no idea of how to implement the IConfiguration interface. Any help is appreciated.
With ASP.NET Core 2.x you no longer need to register the IConfiguration type yourself. Instead, the framework will already register it with the dependency injection container for you. So you can just inject IConfiguration in your services directly.
You can also take a look at the options pattern to see how to implement the configuration for your own service layer. So you could do it like this:
services.Configure<MyDatabaseOptions>(options =>
{
options.ConnectionString = Configuration.GetConnectionString("DefaultConnection");
});
Assuming a MyDatabaseOptions type that you inject into your service using the options pattern.

Injecting a service singleton into actor (Akka.NET) in ASP.NET Core

I am trying to inject a singleton of a service into an actor (Akka.NET) with ASP.NET Core's built-in DI container.
I have done the following in ConfigureServices:
public void ConfigureServices(IServiceCollection services)
{
// ..
// Register singleton of service
services.AddSingleton<IMyService, MyService>();
// Build service provider
var provider = services.BuildServiceProvider();
// Create actor system
var system = ActorSystem.Create("MyActorSystem");
// Inject service singleton into actor
directory.MyActorRef
= system.ActorOf(MyActor.Props(provider.GetService<IMyService>()), "myactor");
}
The issue is that the instance of MyService in the actor is different from the instance that is injected into the rest of the application - i.e. it is not a singleton.
What am I doing wrong and is there a better way of doing this?
That's because you create a separate IoC container inside your ConfigureServices
// Build service provider
var provider = services.BuildServiceProvider();
This line will create a new service provider (IoC container). When you resolve services from it, they are effectively singletons (since its not resolved from a scoped provider).
You shouldn't ever call .BuildServiceProvider() inside your ConfigureServices method, except when using 3rd party container and create it (i.e. when using Autofac).
Anyways, if you for some reason have to create the provider inside of ConfigureServices you need to change signature of ConfigureServices to
// Return value from void to IServiceProvider
public IServiceProvider ConfigureServices(IServiceCollection services)
{
var provider = services.BuildServiceProvider();
// don't call services.AddXxx(..) after this point! The container is already created and its registrations can't be changed
...
return provider;
}
This will make ASP.NET Core use this container instead of creating its own one and passing that to Configure Method.
While this may solve you immediate problem, its not very clean to do that kind of resolving inside ConfigureServices and you should use the docs (or ask a separate question) on how to correctly use DI with Akka.NET (Sorry not familiar with it, I'm Microsoft Orleans user :)).
A slightly better (still not fully correct since it works around the idea of DI) way would be to delay the instantiation of the actor until Configure method is called.
public void ConfigureServices(IServiceCollection services)
{
// ..
// Register singleton of service
services.AddSingleton<IMyService, MyService>();
}
public void Configure(IApplicationBuilder app)
{
// Create actor system
var system = ActorSystem.Create("MyActorSystem");
// Inject service singleton into actor
directory.MyActorRef
= system.ActorOf(MyActor.Props(app.ApplicationServices.GetService<IMyService>()), "myactor");
}
or
public void ConfigureServices(IServiceCollection services)
{
// ..
// Register singleton of service
services.AddSingleton<IMyService, MyService>();
}
// inject it in Configure
public void Configure(IApplicationBuilder app, IMyService myService)
{
// Create actor system
var system = ActorSystem.Create("MyActorSystem");
// Inject service singleton into actor
directory.MyActorRef
= system.ActorOf(MyActor.Props(myService), "myactor");
}
This will initialize and resolve your services in Configure.
Remarks regarding singletons, scopes and actors
P.S. keep in mind, you can't resolve scoped services from app.ApplicationServices or the service provider, it will throw an exception. This may become an issue when you want to use DbContext which, by default is registered as scoped service.
You can also register it as scoped with an override to AddDbContext, but be aware of "memory leaks", as the number of tracked objects grows, so will the memory consumption (and big number of tracked entities (>=10k) will decrease your tracker related operations significantly).
And with DbContext in mind, also keep in mind that EF and EF Core are not thread-safe, and can't be accessed by threads (or run multiple asynchronous operations, i.e. starting 5 queries w/o awaiting and then using await Task.WaitAll(...)).
While an actor is guaranteed to only be accessed by a single thread at a single time, the services aren't if you scope them.
How well this works depends on the Task Scheduler implementation used by Akka.NET (again, not familiar with it's internals - i.e. Orleans abstracts persistence behind storage providers).