Setting AWS Services Lifetime in .NET Core - c#

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.

Related

Dependency Injection in a .NET 6 class project without controllers and HTTP

When you create a regular .NET 5 or 6 API project, you get some basic classes such as Program.cs and Startup.cs. I want to replicate that in a class project, because I want to be able to configure my services for dependency injection, but I don't want any controllers or HTTP in my project. As an example, let's assume I want to create a .NET 6 project using minimal API/hosting, and I want to check for file changes in a directory:
Program.cs
static async Task Main(string[] args)
{
await CreateHostBuilder(args).Build().RunAsync();
}
static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureServices((_, services) => ConfigureServices(services));
static void ConfigureServices(IServiceCollection services)
{
services.AddTranscient<IFileListener, FileListener>();
}
This is probably a good starting point, which is quite similar to Startup.cs in an API project.
Inside my FileListener class, I want to call a method, that listens for file changes in a folder. Let's call it StartListening(). Where would I call that method? At some point I guess I need to do something like:
var fileListenerService = ((IServiceCollection)services).BuildServiceProvider().GetService<IListener>();
await fileListenerService.StartListening();
But where? Inside the Main method? Inside ConfigureServices? Somewhere else?
Maybe I'm looking at this the wrong way, but essentially I just need to call a method and make it run that method until the application is closed.
Microsoft's hosting has a concept of hosted services to handle background tasks, so you can turn your FileListener into hosted service and register it in DI with AddHostedService and the hosting will start it automatically with DI and cancelation signaling support.
Note that consuming scoped services (like EF context with default registration) from the hosted service requires a little bit extra work.

How can I set up a middleware in a .NET Core 3.1 Azure Functions project? trying to dependency inject an external service that requires middleware

As the title says,
How can I set up a middleware in a .NET Core 3.1 Azure Functions project? trying to dependency inject an external service that requires middleware.
First off, there are some problems here.
The Function app you create in Visual Studio 19, doesn't contain a Startup.cs class.
So we have to create this manually. Then there's a problem that it's not behaving like a real Startup class. It needs to inherit FunctionsStartup.
This is achieved by adding this line of code before the namespace first for some reason.
[assembly: FunctionsStartup(typeof(test_project.Startup))]
Then we need to inherit FunctionsStartup and then implement it.
public override void Configure(IFunctionsHostBuilder builder)
{
}
So after this, we are able to Add stuff like Singleton or external service like so,
public override void Configure(IFunctionsHostBuilder builder)
{
builder.Services.AddSomeExternalService();
builder.Services.AddSingleton<SomeOtherStuff>(
new SomeOtherStuff(config, env_SomeOtherStuff));
}
But now my real problem starts. We need to add middleware for some functionality to work in the external service.
Usually, you can do this in a web applications (not function app) like so,
public void Configure(IApplicationBuilder app)
{
app.UseSomeExternalServiceMiddleware();
}
The problem is, I can't figure out how to do this in a function app with core 3.1
maybe it's not implemented the same way, I don't know why.
Is there a workaround for this sort of problem?
There is no direct way to do this but there is a proposed feature that you can refer to.
More References :
Dependency Injection in Azure Functions with C# (twilio.com)
c# - Azure Functions Runtime v3 Middleware - Stack Overflow
Be able to overwrite http response in IFunctionsWorkerMiddleware · Issue #530 · Azure/azure-functions-dotnet-worker · GitHub

Upgrade to .NET Core 3.1 - Can't instantiate singleton PhysicalFileProvider in services

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.

How to add all registered services from Blazor to Simple Injector?

I have a server side blazor application and I'm also using simple injector for other dependency injections in my application.
I want to register all services from blazor to the simple injector container because otherwise I will have to duplicate all service registration but also the main problem is that there's some services registrations that I don't know what is the correct way of registering (usually comes from some dependency injection extension library).
For example, I need something like
public void ConfigureServices(IServiceCollection services)
{
// multiple service registration
services.RegisterSomeServices();
// ...
// some how register all services into simple injector container
container.SomeHowRegisterServices();
}
How can I get all registered services from blazor and register in the simple injector container?
After some time searching, I found in the docs a ServiceCollection Integration Guide which is a way of integrating third party services into the Simple Injector.
What I need to do according to Cross wiring framework and third-party services is cross wire blazor services into simple injector, so for my case, what I need to do is
public void ConfigureServices(IServiceCollection services)
{
// multiple service registration
services.RegisterSomeServices();
// ...
// some how register all services into simple injector container
IServiceProvider provider = services
.AddSimpleInjector(simpleInjectorContainer)
.BuildServiceProvider(validateScopes: true);
// Ensures framework components are cross wired.
provider.UseSimpleInjector(simpleInjectorContainer);
}

Custom WebApplicationFactory in integration testing not registering services in Startup.cs (ASP.NET Core 3.1)

I am running into an issue where I am using a custom WebApplicationFactory and it is not registering the services in my Startup.cs. I am using Asp.Net core 3.1 and Xunit.
I have below in my API (startup.cs) registered using extension methods:
public void ConfigureServices(IServiceCollection services)
{
services.AddBaseApiConfiguration(Configuration);
services.AddRepositoryServices();
services.AddApiServices();
services.AddMediatrServices();
}
Per MS documentation:
The SUT's database context is registered in its
Startup.ConfigureServices method. The test app's
builder.ConfigureServices callback is executed after the app's
Startup.ConfigureServices code is executed.
But above is not occurring. None of my services from the startup I am using are being registered (i.e. the 4 extension methods I have are never being called and are never registered). This is causing a few problems: my DB context uses IMediatr in its constructor so that events can be published during context.SaveChangesAsync() (on success). But as my service is never registered, it fails to find it. How do I ensure that this takes place correctly?
Below is my custom factory:
protected override void ConfigureWebHost(IWebHostBuilder builder)
{
builder
.UseEnvironment("Development")
.ConfigureServices(services =>
{
// Remove the app's db context registrations
var descriptor = services.SingleOrDefault(
d => d.ServiceType ==
typeof(DbContextOptions<AppDbContext>));
if (descriptor != null)
{
services.Remove(descriptor );
}
services.AddSingleton<IDbConnectionFactoryService, SqliteConnectionFactoryService>();
// Add a database context using an in-memory
// database for testing.
services.AddDbContext<AppDbContext>(options =>
{
options.UseSqlite("Data Source=sqlitedemo.db");
});
// Build the service provider.
var sp = services.BuildServiceProvider();
// Create a scope to obtain a reference to the database context
using (var scope = sp.CreateScope())
{
var scopedServices = scope.ServiceProvider;
var db = scopedServices.GetRequiredService<AppDbContext>();
// Ensure the database is created.
db .Database.EnsureDeleted();
db .Database.EnsureCreated();
}
});
}
Edit: It seems the services in Startup.cs are being called after the CustomWebApplication factory services. This is completely odd as per .Net core 3.0, the order was changed to be the opposite. So why is this still occuring?
Edit 2: Need to use ConfigureTestServices instead of ConfigureServices.
I didn't find this in the docs but calling ConfigureTestServices ensures that the CustomWebApplicationFactory services are called after Startup services are called. Per the docs, this is not pointed out correctly but at least this might help someone else who ran into the same issue.
If you have just a few integration tests with common mock service registrations, ConfigureTestServices works just fine, but it doesn’t scale well when many tests need their own specific mock registrations. ConfigureTestServices requires that you rebuild the host and its DI container for each case. I developed an extension to Microsoft Dependency Injection that allows local mocks without rebuilding the container. Check it out - Rsi.DependencyInjection.

Categories