GetRequiredService<DbContextOptions<MovieContext>> v.s. GetRequiredService<MovieContext> - c#

I am reading this tutorial and found two approaches used by the author to obtain MovieContext.
In SeedData.Initialize, MovieContext is obtained as follows.
public static class SeedData
{
public static void Initialize(IServiceProvider isp)
{
DbContextOptions<MovieContext> options =
isp.GetRequiredService<DbContextOptions<MovieContext>>();
using (var context = new MovieContext(options))
{
// trimmed for simplicity
}
}
}
But in Program.Main, the context is obtain as follows.
public class Program
{
public static void Main(string[] args)
{
IWebHost iwh = BuildWebHost(args);
using (IServiceScope iss = iwh.Services.CreateScope())
{
IServiceProvider isp = iss.ServiceProvider;
try
{
MovieContext context = isp.GetRequiredService<MovieContext>();
// trimmed for simplicity
}
}
}
}
Question
Is there any difference between
new MovieContext(isp.GetRequiredService<DbContextOptions<MovieContext>>());
and
isp.GetRequiredService<MovieContext>();
where isp is of type IServiceProvider ?

Is there any difference between the two approaches.
In the first example you manually instantiate the context and inject its explicit dependency by using the container to resolve and instantiate the options (Service Locator).
In the second example the container handles everything. It will resolve the option and inject it into the context when it is being resolved.
When do we need to do the former and the latter approach?
Totally a matter of preference. Both can be done as the end result is the same depending on how the context was registered with the IoC container.

Related

How to initialize scoped dependencies for consumers using MassTransit filters?

I would like to initialize some dependencies resolved from the MassTransit serviceProvider in the same way Asp.Net Core does with the pipeline's middlewares.
In particular I would like to inspect the incoming message before the consumer is called and extract the tenant from it (I'm currently working on a multitenant web application with single database per tenant).
With this informations I need to initialize some scoped instances (Ef Core DbContext for example).
I know that I can inject them in the Consumer through constructor but this means that I must do that everytime I write a new one, so I suppose that a filter should be the right place (correct me if I'm wrong).
The problem raises when I need to access the current consumer scope to resolve the dependencies that I need. I was thinking that the behavior of the MassTransit' pipeline was similar to the Asp.Net one regarding middleware injection but I was probably wrong.
I haven't found any documentation on how to do that clearly without cluttering the code of the filter, so any suggestion is going to be really appreciated.
This is the filter that I need to modify:
public class TenantContextInitializerFilter<T> : IFilter<T> where T : class, ConsumeContext
{
public void Probe(ProbeContext context) { }
public async Task Send(T context, IPipe<T> next)
{
//Resolve scoped instance here and do something before Consumer is called
var connectionStringProvider = scope.GetService<IConnectionStringProvider>();
await next.Send(context);
}
}
public class RegistrationsDeliveredEventConsumer : IConsumer<IRegistrationsDelivered>
{
private readonly IConnectionStringProvider _connectionStringProvider;
public RegistrationsDeliveredEventConsumer(IConnectionStringProvider connectionStringProvider)
{
//This should be the same instance that has been resolved in the filter' Send() method
_connectionStringProvider = connectionStringProvider;
}
public async Task Consume(ConsumeContext<IRegistrationsDelivered> context)
{
}
}
This is a simplified example of my code but this should be enough
There's two facets to consider: 1) are filters registered as services/pulled from the service collection when using the ASP.NET Core integration and 2) what lifetime do the filters have if they are. I'm not familiar with the MassTransit ASP.NET Core integration, but it looks like you should be good based on a cursory review. You'll need to confirm that both of those requirements are met.
For dependency injection, in general, constructor injection is the way to go unless there's a very specific need to do something different, which does not seem to be the case here. In short, you need a constructor for your filter.
What exactly you need to inject is a function of the lifetime of the filter. If it has a transient lifetime, then you can inject your scoped dependencies directly. If it has a singleton lifetime, then you'll need to inject IServiceProvider instead, and do the following whenever you need to use one of those dependencies:
using (var scope = _serviceProvider.CreateScope())
{
var dep = scope.ServiceProvider.GetRequiredService<MyDependency>();
// do something with `dep`
}
Here's a draft... I'm sure there are missing pieces, so let me know if you have questions.
public class TenantContextInitializerFilter<T> : IFilter<T> where T : class, ConsumeContext
{
private readonly Func<string, IDbConnection> _dbContextAccessor;
public void Probe(ProbeContext context) { }
public TenantContextInitializerFilter(Func<string, IDbConnection> dbContextAccessor)
{
_dbContextAccessor = dbContextAccessor;
}
public async Task Send(T context, IPipe<T> next)
{
var tenantId = ""; // place holder
using (var dbContext = _dbContextAccessor(tenantId))
{
//... do db logic
}
await next.Send(context);
}
}
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<IConnectionStringProvider>(
provider => null /* TODO figure out how to fetch scoped instance from a cache or some storage mechanism*/);
services.AddScoped(provider =>
{
IDbConnection Accessor(string tenantId)
{
if (provider.GetService<IConnectionStringProvider>()
.TryGetConnectionString(tenantId, out var connectionString, out var providerName))
return new SqlConnection(connectionString);
throw new Exception();
}
return (Func<string, IDbConnection>)Accessor;
});
}
}

Accessing dbContext in a C# console application

I have tried to figure this out, but I am stuck.
I have a Net Core 2 application with Service/Repo/Api/Angular layers - but now I want to 'bolt on' a console application and access all the goodies I have already built up. I seem to be in a mess of static objects and DI and null parameters. Anyway, here is a simplified version of my code.
namespace SimpleExample
{
class Program
{
private static ApplicationDbContext _appDbContext;
public Program(ApplicationDbContext appDbContext)
{
_appDbContext = appDbContext;
}
static void Main(string[] args)
{
var instance = new Program(); // this doesn't work!
var instance = new Program(_appDbContext); // neither does this!
instance.GetData();
}
private void GetData()
{
Console.WriteLine("Let's read some data! Press a key to continue.");
Console.ReadLine();
var data = "my data";
var result = GetId(data);
}
private string GetId(string original)
{
var data = _appDbContext.Data
.Where(x => x.Name == original.Trim)
.FirstOrDefault();
return data;
}
}
}
I am getting the classic
'An object reference is required for the non-static field'
error. Then from investigating on here I changed things to static and then everything becomes null.
It's not just the DbContext I am trying to inject. I'm also trying to inject
private ManagerService _managerService;
but getting same errors.
Update
If I try
private static ApplicationDbContext _appDbContext = new
ApplicationDbContext();
as suggested a few times below, then I get the error
There is no argument given that corresponds to the required formal
parameter 'options' of
'ApplicationDbContext.ApplicationDbContext(DbContextOptions)'
OK, I have figured this out, and I'll post my answer for anyone else struggling in this situation.
When you launch the console app, your normal startup.cs doesn't execute, so you have to put a lot of that code in your console app.
private static SiteService _siteService;
private static ApplicationDbContext _appDbContext;
public static void Main()
{
var services = new ServiceCollection();
services.AddTransient<ISiteInterface, SiteRepo>();
services.AddTransient<SiteService>();
services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer("blah-blah"));
var serviceProvider = services.BuildServiceProvider();
_siteService = serviceProvider.GetService<SiteService>();
_appDbContext = serviceProvider.GetService<ApplicationDbContext>();
GetData();
}
and now your _appDbContext will be available throughout the rest of your console app.
Hope that helps!
Basically, if you do not plan extensive usage of DbContext nor use DI, there is no need for ServiceProvider. Just remember to make DbContext instance short living and use it for single unit-of-work, not longer.
Your context may look like this:
using Microsoft.EntityFrameworkCore;
namespace YourNamespace;
public class ApplicationContext : DbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(#"Your conn string");
}
public DbSet<YourType> YourEntity { get; set; }
}
You can pass conn string by ApplicationContext ctor as well. This is nicely explained here by Microsoft .
Then you can utilise your ApplicationContext like this:
// Unit-of-work closed in using statement
// Here you can query/update your DbContext
using (var dbContext = new ApplicationContext())
{
var queryResult = dbContext.YourEntity.Where(....);
}
You can prepare number of such units-of-work as separate methods for querying a database.
Your repository service can consist of these methods.
Then you can instantiate the service as needed.

Factory Pattern with Open Generics

In ASP.NET Core, one of the things you can do with Microsoft's dependency injection framework is bind "open generics" (generic types unbound to a concrete type) like so:
public void ConfigureServices(IServiceCollection services) {
services.AddSingleton(typeof(IRepository<>), typeof(Repository<>))
}
You can also employ the factory pattern to hydrate dependencies. Here's a contrived example:
public interface IFactory<out T> {
T Provide();
}
public void ConfigureServices(IServiceCollection services) {
services.AddTransient(typeof(IFactory<>), typeof(Factory<>));
services.AddSingleton(
typeof(IRepository<Foo>),
p => p.GetRequiredService<IFactory<IRepository<Foo>>().Provide()
);
}
However, I have not been able to figure out how to combine the two concepts together. It seems like it would start with something like this, but I need the concrete type that is being used to hydrate an instance of IRepository<>.
public void ConfigureServices(IServiceCollection services) {
services.AddTransient(typeof(IFactory<>), typeof(Factory<>));
services.AddSingleton(
typeof(IRepository<>),
provider => {
// Say the IServiceProvider is trying to hydrate
// IRepository<Foo> when this lambda is invoked.
// In that case, I need access to a System.Type
// object which is IRepository<Foo>.
// i.e.: repositoryType = typeof(IRepository<Foo>);
// If I had that, I could snag the generic argument
// from IRepository<Foo> and hydrate the factory, like so:
var modelType = repositoryType.GetGenericArguments()[0];
var factoryType = typeof(IFactory<IRepository<>>).MakeGenericType(modelType);
var factory = (IFactory<object>)p.GetRequiredService(factoryType);
return factory.Provide();
}
);
}
If I try to use the Func<IServiceProvider, object> functor with an open generic, I get this ArgumentException with the message Open generic service type 'IRepository<T>' requires registering an open generic implementation type. from the dotnet CLI. It doesn't even get to the lambda.
Is this type of binding possible with Microsoft's dependency injection framework?
The net.core dependency does not allow you to provide a factory method when registering an open generic type, but you can work around this by providing a type that will implement the requested interface, but internally it will act as a factory. A factory in disguise:
services.AddSingleton(typeof(IMongoCollection<>), typeof(MongoCollectionFactory<>)); //this is the important part
services.AddSingleton(typeof(IRepository<>), typeof(Repository<>))
public class Repository : IRepository {
private readonly IMongoCollection _collection;
public Repository(IMongoCollection collection)
{
_collection = collection;
}
// .. rest of the implementation
}
//and this is important as well
public class MongoCollectionFactory<T> : IMongoCollection<T> {
private readonly _collection;
public RepositoryFactoryAdapter(IMongoDatabase database) {
// do the factory work here
_collection = database.GetCollection<T>(typeof(T).Name.ToLowerInvariant())
}
public T Find(string id)
{
return collection.Find(id);
}
// ... etc. all the remaining members of the IMongoCollection<T>,
// you can generate this easily with ReSharper, by running
// delegate implementation to a new field refactoring
}
When the container resolves the MongoCollectionFactory it will know what type T is and will create the collection correctly. Then we take that created collection save it internally, and delegate all calls to it. ( We are mimicking this=factory.Create() which is not allowed in csharp. :))
Update:
As pointed out by Kristian Hellang the same pattern is used by ASP.NET Logging
public class Logger<T> : ILogger<T>
{
private readonly ILogger _logger;
public Logger(ILoggerFactory factory)
{
_logger = factory.CreateLogger(TypeNameHelper.GetTypeDisplayName(typeof(T)));
}
void ILogger.Log<TState>(...)
{
_logger.Log(logLevel, eventId, state, exception, formatter);
}
}
original discussion here:
https://twitter.com/khellang/status/839120286222012416
See this issue on the dotnet (5) runtime git.
This will add support to register open generics via a factory.
I was dissatisfied with the existing solutions as well.
Here is a full solution, using the built-in container, that supports everything we need:
Simple dependencies.
Complex dependencies (requiring the IServiceProvider to be resolved).
Configuration data (such as connection strings).
We will register a proxy of the type that we really want to use. The proxy simply inherits from the intended type, but gets the "difficult" parts (complex dependencies and configuration) through a separately registered Options type.
Since the Options type is non-generic, it is easy to customize as usual.
public static class RepositoryExtensions
{
/// <summary>
/// A proxy that injects data based on a registered Options type.
/// As long as we register the Options with exactly what we need, we are good to go.
/// That's easy, since the Options are non-generic!
/// </summary>
private class ProxyRepository<T> : Repository<T>
{
public ProxyRepository(Options options, ISubdependency simpleDependency)
: base(
// A simple dependency is injected to us automatically - we only need to register it
simpleDependency,
// A complex dependency comes through the non-generic, carefully registered Options type
options?.ComplexSubdependency ?? throw new ArgumentNullException(nameof(options)),
// Configuration data comes through the Options type as well
options.ConnectionString)
{
}
}
public static IServiceCollection AddRepositories(this ServiceCollection services, string connectionString)
{
// Register simple subdependencies (to be automatically resolved)
services.AddSingleton<ISubdependency, Subdependency>();
// Put all regular configuration on the Options instance
var optionObject = new Options(services)
{
ConnectionString = connectionString ?? throw new ArgumentNullException(nameof(connectionString))
};
// Register the Options instance
// On resolution, last-minute, add the complex subdependency to the options as well (with access to the service provider)
services.AddSingleton(serviceProvider => optionObject.WithSubdependency(ResolveSubdependency(serviceProvider)));
// Register the open generic type
// All dependencies will be resolved automatically: the simple dependency, and the Options (holding everything else)
services.AddSingleton(typeof(IRepository<>), typeof(ProxyRepository<>));
return services;
// Local function that resolves the subdependency according to complex logic ;-)
ISubdependency ResolveSubdependency(IServiceProvider serviceProvider)
{
return new Subdependency();
}
}
internal sealed class Options
{
internal IServiceCollection Services { get; }
internal ISubdependency ComplexSubdependency { get; set; }
internal string ConnectionString { get; set; }
internal Options(IServiceCollection services)
{
this.Services = services ?? throw new ArgumentNullException(nameof(services));
}
/// <summary>
/// Fluently sets the given subdependency, allowing to options object to be mutated and returned as a single expression.
/// </summary>
internal Options WithSubdependency(ISubdependency subdependency)
{
this.ComplexSubdependency = subdependency ?? throw new ArgumentNullException(nameof(subdependency));
return this;
}
}
}
I also don't understand the point of your lambda expression so I'll explain to you my way of doing it.
I suppose what you wish is to reach what is explained in the article you shared
This allowed me to inspect the incoming request before supplying a dependency into the ASP.NET Core dependency injection system
My need was to inspect a custom header in the HTTP request to determine which customer is requesting my API. I could then a bit later in the pipeline decide which implementation of my IDatabaseRepository (File System or Entity Framework linked to a SQL Database) to provide for this unique request.
So I start by writing a middleware
public class ContextSettingsMiddleware
{
private readonly RequestDelegate _next;
public ContextSettingsMiddleware(RequestDelegate next, IServiceProvider serviceProvider)
{
_next = next;
}
public async Task Invoke(HttpContext context, IServiceProvider serviceProvider, IHostingEnvironment env, IContextSettings contextSettings)
{
var customerName = context.Request.Headers["customer"];
var customer = SettingsProvider.Instance.Settings.Customers.FirstOrDefault(c => c.Name == customerName);
contextSettings.SetCurrentCustomer(customer);
await _next.Invoke(context);
}
}
My SettingsProvider is just a singleton that provides me the corresponding customer object.
To let our middleware access this ContextSettings we first need to register it in ConfigureServices in Startup.cs
var contextSettings = new ContextSettings();
services.AddSingleton<IContextSettings>(contextSettings);
And in the Configure method we register our middleware
app.UseMiddleware<ContextSettingsMiddleware>();
Now that our customer is accessible from elsewhere let's write our Factory.
public class DatabaseRepositoryFactory
{
private IHostingEnvironment _env { get; set; }
public Func<IServiceProvider, IDatabaseRepository> DatabaseRepository { get; private set; }
public DatabaseRepositoryFactory(IHostingEnvironment env)
{
_env = env;
DatabaseRepository = GetDatabaseRepository;
}
private IDatabaseRepository GetDatabaseRepository(IServiceProvider serviceProvider)
{
var contextSettings = serviceProvider.GetService<IContextSettings>();
var currentCustomer = contextSettings.GetCurrentCustomer();
if(SOME CHECK)
{
var currentDatabase = currentCustomer.CurrentDatabase as FileSystemDatabase;
var databaseRepository = new FileSystemDatabaseRepository(currentDatabase.Path);
return databaseRepository;
}
else
{
var currentDatabase = currentCustomer.CurrentDatabase as EntityDatabase;
var dbContext = new CustomDbContext(currentDatabase.ConnectionString, _env.EnvironmentName);
var databaseRepository = new EntityFrameworkDatabaseRepository(dbContext);
return databaseRepository;
}
}
}
In order to use serviceProvider.GetService<>() method you will need to include the following using in your CS file
using Microsoft.Extensions.DependencyInjection;
Finally we can use our Factory in ConfigureServices method
var databaseRepositoryFactory = new DatabaseRepositoryFactory(_env);
services.AddScoped<IDatabaseRepository>(databaseRepositoryFactory.DatabaseRepository);
So every single HTTP request my DatabaseRepository will may be different depending of several parameters. I could use a file system or a SQL Database and I can get the proper database corresponding to my customer. (Yes I have multiple databases per customer, don't try to understand why)
I simplified it as possible, my code is in reality more complex but you get the idea (I hope). Now you can modify this to fit your needs.

Dependency injection using Azure WebJobs SDK?

The problem is that the Azure WebJobs SDK supports only public static methods as job entry-points which means there is no way of implementing constructor/property injection.
I am unable to find anything about this topic in official WebJobs SDK documentation/resources. The only solution that I came across is based on service locator (anti) pattern described on this post here.
Is there a good way to use "proper" dependency injection for projects based on Azure WebJobs SDK?
Azure WebJobs SDK now supports instance methods. Combining this with a custom IJobActivator allows you to use DI.
First, create the custom IJobActivator that can resolve a job type using your favourite DI container:
public class MyActivator : IJobActivator
{
private readonly IUnityContainer _container;
public MyActivator(IUnityContainer container)
{
_container = container;
}
public T CreateInstance<T>()
{
return _container.Resolve<T>();
}
}
You need to register this class using a custom JobHostConfiguration:
var config = new JobHostConfiguration
{
JobActivator = new MyActivator(myContainer)
};
var host = new JobHost(config);
Then, you can use a simple class with instance methods for your jobs (here I'm using Unity's constructor injection feature):
public class MyFunctions
{
private readonly ISomeDependency _dependency;
public MyFunctions(ISomeDependency dependency)
{
_dependency = dependency;
}
public Task DoStuffAsync([QueueTrigger("queue")] string message)
{
Console.WriteLine("Injected dependency: {0}", _dependency);
return Task.FromResult(true);
}
}
This is how I handled scoping using the new SDK. Using the IJobactivator as described by Alexander Molenkamp.
public class ScopedMessagingProvider : MessagingProvider
{
private readonly ServiceBusConfiguration _config;
private readonly Container _container;
public ScopedMessagingProvider(ServiceBusConfiguration config, Container container)
: base(config)
{
_config = config;
_container = container;
}
public override MessageProcessor CreateMessageProcessor(string entityPath)
{
return new CustomMessageProcessor(_config.MessageOptions, _container);
}
private class CustomMessageProcessor : MessageProcessor
{
private readonly Container _container;
public CustomMessageProcessor(OnMessageOptions messageOptions, Container container)
: base(messageOptions)
{
_container = container;
}
public override Task<bool> BeginProcessingMessageAsync(BrokeredMessage message, CancellationToken cancellationToken)
{
_container.BeginExecutionContextScope();
return base.BeginProcessingMessageAsync(message, cancellationToken);
}
public override Task CompleteProcessingMessageAsync(BrokeredMessage message, FunctionResult result, CancellationToken cancellationToken)
{
var scope = _container.GetCurrentExecutionContextScope();
if (scope != null)
{
scope.Dispose();
}
return base.CompleteProcessingMessageAsync(message, result, cancellationToken);
}
}
}
You can the use your custom MessagingProvider in your JobHostConfiguration like
var serviceBusConfig = new ServiceBusConfiguration
{
ConnectionString = config.ServiceBusConnectionString
};
serviceBusConfig.MessagingProvider = new ScopedMessagingProvider(serviceBusConfig, container);
jobHostConfig.UseServiceBus(serviceBusConfig);
After asking my own question about how to handle scoping ... I've just came up to this solution: I don't think this is ideal but I couldn't find any other solution for the moment.
In my example I am dealing with ServiceBusTrigger.
As I am using SimpleInjector, the implementation of the IJobActivator interface looks like that:
public class SimpleInjectorJobActivator : IJobActivator
{
private readonly Container _container;
public SimpleInjectorJobActivator(Container container)
{
_container = container;
}
public T CreateInstance<T>()
{
return (T)_container.GetInstance(typeof(T));
}
}
Here, I am dealing with Triggered webjobs.
So I have two dependencies:
A singleton:
public interface ISingletonDependency { }
public class SingletonDependency : ISingletonDependency { }
And another that need to live only the time my function is triggered:
public class ScopedDependency : IScopedDependency, IDisposable
{
public void Dispose()
{
//Dispose what need to be disposed...
}
}
So in order to have a process that run independently from the webjob. I've encapsulated my process into a class :
public interface IBrokeredMessageProcessor
{
Task ProcessAsync(BrokeredMessage incommingMessage, CancellationToken token);
}
public class BrokeredMessageProcessor : IBrokeredMessageProcessor
{
private readonly ISingletonDependency _singletonDependency;
private readonly IScopedDependency _scopedDependency;
public BrokeredMessageProcessor(ISingletonDependency singletonDependency, IScopedDependency scopedDependency)
{
_singletonDependency = singletonDependency;
_scopedDependency = scopedDependency;
}
public async Task ProcessAsync(BrokeredMessage incommingMessage, CancellationToken token)
{
...
}
}
So now when the webjob starts, I need to register my dependencies depending their scopes:
class Program
{
private static void Main()
{
var container = new Container();
container.Options.DefaultScopedLifestyle = new ExecutionContextScopeLifestyle();
container.RegisterSingleton<ISingletonDependency, SingletonDependency>();
container.Register<IScopedDependency, ScopedDependency>(Lifestyle.Scoped);
container.Register<IBrokeredMessageProcessor, BrokeredMessageProcessor>(Lifestyle.Scoped);
container.Verify();
var config = new JobHostConfiguration
{
JobActivator = new SimpleInjectorJobActivator(container)
};
var servicebusConfig = new ServiceBusConfiguration
{
ConnectionString = CloudConfigurationManager.GetSetting("MyServiceBusConnectionString")
};
config.UseServiceBus(servicebusConfig);
var host = new JobHost(config);
host.RunAndBlock();
}
}
And this is the triggered job:
Only have one dependency : the IoC container. Because this class is part of my composition root, it should be ok.
It handle the scope into the triggered function.
public class TriggeredJob
{
private readonly Container _container;
public TriggeredJob(Container container)
{
_container = container;
}
public async Task TriggeredFunction([ServiceBusTrigger("queueName")] BrokeredMessage message, CancellationToken token)
{
using (var scope = _container.BeginExecutionContextScope())
{
var processor = _container.GetInstance<IBrokeredMessageProcessor>();
await processor.ProcessAsync(message, token);
}
}
}
I've used a couple patterns that rely on the concept of child containers/scopes (depending on the terminology of your IoC container of choice). Not sure which ones support it, but I can tell you that StructureMap 2.6.x and AutoFac do.
The idea is to spin up a child scope for each message coming in, inject any context that's unique to that request, resolve the top-level object from the child scope, and then run your process.
Here's some generalized code showing it with AutoFac. It does do a direct resolve from the container, similar to the anti-pattern you're attempting to avoid, but it's been isolated to one place.
In this case, it's using a ServiceBusTrigger to fire the job, but could be anything - a job host could potentially have a list of these for the different queues/processes.
public static void ServiceBusRequestHandler([ServiceBusTrigger("queuename")] ServiceBusRequest request)
{
ProcessMessage(request);
}
This method is called by all instances of the above methods. It wraps creation of the child scope in a using block to make sure things are cleaned up. Then, any objects that would vary per request and contain context used by other dependencies (user/client information, etc) would be created and injected into the child container (in this example, the IRequestContext). Finally, the component doing the work would be resolved from the child container.
private static void ProcessMessage<T>(T request) where T : IServiceBusRequest
{
try
{
using (var childScope = _container.BeginLifetimeScope())
{
// create and inject things that hold the "context" of the message - user ids, etc
var builder = new ContainerBuilder();
builder.Register(c => new ServiceRequestContext(request.UserId)).As<IRequestContext>().InstancePerLifetimeScope();
builder.Update(childScope.ComponentRegistry);
// resolve the component doing the work from the child container explicitly, so all of its dependencies follow
var thing = childScope.Resolve<ThingThatDoesStuff>();
thing.Do(request);
}
}
catch (Exception ex)
{
}
}
All answers to the question are outdated now. Using the latest packages you can easily get constructor injection right out of the box. Two steps are only required:
Create the event handler function as an instance method in a non-static class. Let's call the class QueueFunctions.
Add your class to the list of services.
builder.ConfigureServices(services =>
{
// Add
// dependencies
// here
services.AddScoped<QueueFunctions>();
});
Now, you'll be able to inject dependencies through the constructor.

Overriding AutoFac scoping configuration when using factory

How to configure AutoFac so that I get a new instance of Context every time I hit the factory. The Content component is set to InstancePerLifetimeScope(), which is perfect for 99% of my usage, but now I need a little extra control over how the Context component is scoped.
class Program
{
static void Main(string[] args)
{
var builder = new ContainerBuilder();
builder.RegisterType<Box>();
builder.RegisterType<DbContext>().InstancePerLifetimeScope();
var container = builder.Build();
using (var scope = container.BeginLifetimeScope())
{
var x = scope.Resolve<Box>();
}
Console.ReadKey();
}
}
class Box
{
public Box(DbContext.Factory factory)
{
factory();
factory(); // Want this to generate a NEW instance
Console.WriteLine("Box: {0}", GetHashCode());
}
}
class DbContext
{
public delegate DbContext Factory();
public DbContext()
{
Console.WriteLine("Context: {0}", GetHashCode());
}
}
Obviously, this is a rather simplified snippet of code. The problem I am trying to solve is that I have a huge stream of data coming into a service and I am trying to batch-save to the database. So, if Box can create new UOWs on demand, and release them back for disposal in a timely fashion, then I get a nice clean solution.
Thanks!
You can use Func<Owned<>> which works like a small ILifetimeScope :
public Box(Func<Owned<DbContext>> factory)
{
using (Owned<DbContext> ownedDbContext = factory())
{
// instance1
}
using (Owned<DbContext> ownedDbContext = factory())
{
// instance2
}
}
You can find more details on the Autofac documentation : Owned Instances
Another solution is to inject ILifetimeScope and then create a sub lifetimescope :
public Box(ILifetimeScope scope)
{
using (ILifetimeScope subScope = scope.BeginLifetimeScope())
{
DbContext dbContext = subScope.Resolve<DbContext>();
}
}
or
public Box(ILifetimeScope scope)
{
ILifetimeScope subScope = scope.BeginLifetimeScope();
scope.Disposer.AddInstanceForDisposal(subScope);
DbContext dbContext = subScope.Resolve<DbContext>();
// no need to dispose subScope,
// subScope (and dbContext) will be disposed at the same time as scope
}

Categories