Can I use an AutFac factory to create my DbContext - c#

I am trying to implement an auto-refresh using MemoryCache by specifying a CacheEntryUpdateCallback delegate that is called when the cached item expires.
The delegate calls a method in my repository:
public async Task<List<Foo>> GetFoos()
{
return await _dbContext.Foos.ToListAsync();
}
That throws an exception in the callback because the context has already been disposed (the original HttpRequest has long since returned)
So I tried using an Autofac factory to inject my dependency instead:
public FooRepository(Func<<IFooContext> dbContextFactory)
{
_dbContextFactory = dbContextFactory;
}
public async Task<List<Foo>> GetFoos()
{
return await _dbContextFactory().Foos.ToListAsync();
}
That gave me a different exception:
Instances cannot be resolved and nested lifetimes cannot be created
from this LifetimeScope as it has already been disposed.
What about this "Owned" factory thing?
public FooRepository(Func<Owned<IFooContext>> dbContextFactory)
{
_dbContextFactory = dbContextFactory;
}
public async Task<List<Foo>> GetFoos()
{
using(var factory = _dbContextFactory())
{
return await factory.Value.Foos.ToListAsync();
}
}
Nope, same problem:
Instances cannot be resolved and nested lifetimes cannot be created
from this LifetimeScope as it has already been disposed.
What can I do to get around this problem?

you should have hosted service for long run process and kind of refresh queue to feed it
with hosted service you can get DbContext in temporary scope as follow
public class TimedHostedService : IHostedService
{
private readonly IServiceScopeFactory scopeFactory;
public TimedHostedService(IServiceScopeFactory scopeFactory)
{
this.scopeFactory = scopeFactory;
}
private void DoWork()
{
using (var scope = scopeFactory.CreateScope())
{
var dbContext = scope.ServiceProvider.GetRequiredService<MyDbContext>();
}
}
}
about hosted service

Related

Memory leak in Xamarin Forms app when using DI in a Task

I am creating a Xamarin Forms application, and I am using the Xamarin Profiler to show that I have a memory leak. I have tracked the memory leak down to where it is happening, but I can't understand WHY it is happening.
I have a class (we will call it MyClass for now). And that class is using a Timer to call a service once every second. That service makes a REST call to retrieve a bunch of information, and then serializes the results back into an object....
MyClass:
public class MyClass : ContentPage
{
private readonly IMyService myService;
public MyClass() : base()
{
}
protected override async void OnAppearing()
{
StartTimer();
}
private void StartTimer()
{
Task.Run(async() =>
{
while(true)
{
myService = ((App)App.Current)
.serviceProvider
.GetRequiredService<IMyService>();
//--- everytime I call myService.GetSystemStatus(), my allocated memory continues to rise
MyResponse response = await myService.GetSystemStatus();
Device.BeginInvokeOnMainThread(() =>
{
// update the UI here...
});
await Task.Delay(1000);
}
});
}
}
MyService (Singleton):
public class MyService : IMyService
{
private readonly IMyHttpClientFactory httpClientFactory;
public MyService(IMyHttpClientFactory httpClientFactory)
{
this.httpClientFactory = httpClientFactory;
}
public async Task<MyResponse> GetSystemStatus()
{
return await httpClientFactory.Create().GetAsync<MyResponse>(
"http://example.com/api/status"
);
}
}
MyHttpClientFactory (Singleton):
public class MyHttpClientFactory : IMyHttpClientFactory
{
private readonly IServiceProvider _serviceProvider;
public MyHttpClientFactory(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public MyHttpClient Create()
{
return _serviceProvider.GetRequiredService<MyHttpClient>();
}
}
MyHttpClient:
public class MyHttpClient : IDisposable
{
private HttpClient _httpClient;
public MyHttpClient ()
{
_httpClient = new HttpClient();
_httpClient.Timeout = TimeSpan.FromSeconds(10);
}
public async Task<T> GetAsync<T>(string url) where T : new()
{
string s = await GetStringAsync(url);
return JsonConvert.DeserializeObject<T>(s);
}
public async Task<string> GetStringAsync(string url)
{
using (var response = await _httpClient.GetAsync(url))
{
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
}
}
My services are defined as follows:
public partial class App : Application
public ServiceProvider serviceProvider;
public App()
{
IServiceCollection services = new ServiceCollection();
ConfigureServices(services);
serviceProvider = services.BuildServiceProvider();
InitializeComponent();
}
private void ConfigureServices(IServiceCollection services)
{
services.AddHttpClient<MyHttpClient>("MyHttpClient", x =>
{
x.Timeout = TimeSpan.FromSeconds(5);
});
services.AddSingleton<IMyHttpClientFactory, MyHttpClientFactory>();
services.AddSingleton<IMyService, MyService>();
}
}
Best I can tell, the memory is going up because I am referencing the DI MyService inside a separate thread. But I am not sure if this is the reason or if there is something else that would be causing the leak?
Any advice would be greatly appreciated!!!
Thanks!
From what I understand from your code and your comments, it looks like you're looping by calling StartTimer() inside the Device.StartTimer() method.
According to the documentation, Device.StartTimer() is recurring and will occur every X seconds, depending of your interval parameter.
By removing the call to StartTimer() (the one between t.Dispose() and return false of MyClass.StartTimer, your code should work as expected and you will not create a new timer every x seconds
What could be the cause of the leak:
Your MyHttpClient class implements the IDisposable interface, yet the code to use an instance of this class is not leveraging the disposable nature of the object.
Even though the internal HttpClient instance is wrapped in a using statement, the MyHttpClient instance will not be disposed of as you would expect.
// from MyHttpClient class
public async Task<MyResponse> GetSystemStatus()
{
// no using statement here
return await httpClientFactory.Create().GetAsync<MyResponse>(
"http://example.com/api/status"
);
}
// should be:
public async Task<MyResponse> GetSystemStatus()
{
using (var client = await httpClientFactory.Create())
{
return await client.GetAsync<MyResponse>("http://example.com/api/status");
}
}
Another thing to try is to change the location of the resolution of the MyService instance to inside the Task since this is where it is used. This will allow the task to own the resource, and allow it to be collected when the task is complete.
private void StartTimer()
{
Device.StartTimer(TimeSpan.FromSeconds(1), () =>
{
Task t = Task.Run(async() =>
{
// resolve the service here
myService = ((App)App.Current)
.serviceProvider
.GetRequiredService<IMyService>();
MyResponse response = await myService.GetSystemStatus();
Device.BeginInvokeOnMainThread(() =>
{
// update the UI here...
});
});
t.Wait();
t.Dispose();
StartTimer();
return false;
});
}
A couple of additional observations of your code:
In your HttpClientFactory's Create() method, you are resolving an instance of your client from the DI container.
Your MyHttpClient class has a default constructor which means the resolution is not needed since there are no additional dependencies requiring DI support.
Your code could simply return a new MyHttpClient() instance from the Create() method without the need for DI.
Your MyHttpClient also implements the IMyHttpClient interface, but your factory returns the concrete type. This means you need to either remove the interface as unnecessary or change the return type to be the interface type since the interface is redundant unless it is used.
Thank you all for your answers....
I finally figured out the source of the memory leak.
The problem was that I was referencing "MyService" like this:
myService = ((App)App.Current)
.serviceProvider
.GetRequiredService<IMyService>();
The problem was that the serviceProvider object was a public property on my App. So each time I referenced the provider inside my loop, it was creating the leak.
To get around this, I added an abstract method to each of my pages that implemented MyClass to return the service correctly using DI. This has corrected my memory leak issue....
Thanks all for the help!
I don't think that your timer logic is the cause of the leak.
But in case it is useful to you, here is a clean way to do work periodically, yet if work takes a long time, avoid events "piling up".
Given await/async, no Timer is needed.
(There is an alternative solution that starts/stops a single System.Timers.Timer, but I won't go into that here.)
Replace StartTimer() declaration with the following:
/// <summary> Runs until keepRunning() returns false.
/// Delays by "msecDelay" AFTER finishing the previous loop's non-UI work. </summary>
private void StartTaskLoopWhileKeepRunning(Func<bool> keepRunning, int msecDelay = 250)
{
Task.Run(async () =>
{
while (keepRunning())
{
// Do non-UI work here.
// ... possibly slow work ...
Device.BeginInvokeOnMainThread(() =>
{
// NOTE: This work will run in parallel with the next delay.
// ... Do UI work here. ...
});
// Non-UI thread sleeps for msec.
await Task.Delay(msecDelay);
}
});
}

IHostedService Error in ASP.NET Core app - why is the object already disposed?

I have created a Background Service in my Server Solution
public class PurgeService : IHostedService, IDisposable
{
private readonly IServiceProvider _provider;
private Timer timer;
public PurgeService(IServiceProvider serviceProvider)
{
using (IServiceScope scope = serviceProvider.CreateScope())
{
_provider = scope.ServiceProvider;
}
}
public void Dispose()
{
timer?.Dispose();
}
public Task Purge(IServiceProvider serviceProvider)
{
var dbcontext = serviceProvider.GetRequiredService<ApplicationDBContext>();
var setting = dbcontext.AppSet.First();
double deletetime = setting.PurgeTimer *(1);
DateTime deletedate = DateTime.Now.AddHours(deletetime);
string deleteSQL = $"DELETE FROM Notifications WHERE CreatedDate > {deletedate}"
}
public Task StartAsync(CancellationToken cancellationToken)
{
timer = new Timer(x => Purge(_provider), null, TimeSpan.Zero, TimeSpan.FromSeconds(10));
return Task.CompletedTask;
}
public Task StopAsync(CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
}
And added it to the Startup.cs
services.AddHostedService<PurgeService>();
My goal is to have a background service that checks every 10 seconds if there are notifications older than allowed and deletes them.
But when I run the app an error occurs
"System.ObjectDisposedException: "Cannot access a disposed object."
How can I implement this correctly?
Your constructor seems to be establishing a scope, and immediately disposing the scope. Your provider is tied to that scope so gets nuked immediately in the constructor when Dispose() is called on the scope due to using.
Background services are usually singletons with a lifetime equivalent to the lifetime of the the application. It seems to me you should register your service as a singleton outside of the service class itself. Something like
public class PurgeService : IHostedService
{
// no weird constructor taking in IServiceProvider
}
Also, using an IoC inside of a class is a bit of an antipattern. Inject a DB context factory instead of trying to resolve through a container inside your class.
The problem was that the database table was empty, but the null exception threw a completely different exception.

Can I clone DbContext from existing one?

I'm working on .NET Core Web API and I have one endpoint where I want to run three operations in parallel. All three of them use the same database, so I need three copies of DbContext. I created a simple Factory class, which I later inject into my "Data" class.
Is it possible (if it's, is a good practice), to inject DbContext into my factory class (using built in .NET Core IoC) and when someone calls "CreateMyDbContext" method, just deep clone the one which was injected at the beginning?
EDIT:
Here is the example with the DbContext Pool:
public class FooData : IFooData
{
private readonly Func<DisposableScopedContextWrapper> _func;
public FooData(Func<DisposableScopedContextWrapper> func)
{
_func = func;
}
public async Task<List<Apple>> GetApples()
{
using (var wrapper = _func())
{
var apples = await wrapper.Context.Apples.FromSqlRaw("SELECT.... complicated query").ToListAsync();
return apples;
}
}
public async Task<List<Orange>> GetOranges()
{
using (var wrapper = _func())
{
var oranges = await wrapper.Context.Oranges.FromSqlRaw("SELECT.... complicated query").ToListAsync();
return oranges;
}
}
}
public class FooService
{
private readonly IFooData _fooData;
public FooData(IFooData fooData)
{
_fooData = fooData;
}
public async Task<List<Fruit>> GetFruits()
{
var appleTask = _fooData.GetApples();
var orangeTask = _fooData.GetOranges();
(var result1, var result2) = await (appleTask, orangeTask).WhenAll();
// ...
}
}
I definitely would not recommend any deepcloning for multiple reasons, one of them being that you will need to figure out a lot of EF internals to make it right, and internals can change (and you will need to spend some time on it).
Second option would be just creating your context manually, which I would recommend against also cause modern infrastructure uses DbContext pooling.
So what you can to register Func<DbContext> (or create your own factory) like this:
services.AddSingleton<Func<DbContext>>(provider => () =>
{
var scope = provider.CreateScope();
return scope.ServiceProvider.GetRequiredService<DbContext>();
});
the issue here is that scope here would not be disposed and you can't (if you have default scope for your DbContext) dispose the scope inside the Func cause your context will be disposed also. So you can try creating some disposable wrapper so you can manually dispose everything like this:
public class DisposableScopedContextWrapper : IDisposable
{
private readonly IServiceScope _scope;
public DbContext Context { get; }
public DisposableScopedContextWrapper(IServiceScope scope)
{
_scope = scope;
Context = _scope.ServiceProvider.GetService<DbContext>();
}
public void Dispose()
{
_scope.Dispose();
}
}
services.AddSingleton<Func<DisposableScopedContextWrapper>>(provider =>() =>
{
var scope = provider.CreateScope();
return new DisposableScopedContextWrapper(scope);
});
Inject in your classes Func<DisposableScopedContextWrapper> func and use it
using (var wrapper = func())
{
wrapper.Context...
}

couldnt able to make Autofac nested scopes work (nested multiple Unit of works should have a new dbcontext )

Im trying to implement Unit of Work with Autofac and Mediatr.
Here how is the flow
but i couldn't make Autofac to send same instance of Unit OfWork (which takes DbContext as parameter) inside a scope.
I want to execute that whole scope inside a single transaction, that means when
i get to the point processHandler it should create a instance of DbContext and
share the same instance into nested handlers. such that i can create a transaction on processhandler level and share the same transaction to nested handlers.
here is my DI setup
builder.Register(ctx =>
{
var contextSvc = ctx.Resolve<IContextService>(); // owin context
var connBuilder = ctx.Resolve<IDbConnectionBuilder>();
return SapCommandDb.Create(contextSvc.GetMillCode(), connBuilder.BuildConnectionAsync(IntegrationConnectionName, contextSvc.GetMillCode()).Result);
}).AsSelf().InstancePerLifetimeScope();
builder.RegisterGeneric(typeof(Repository<>)).As(typeof(IDomainRepository<>)).InstancePerLifetimeScope();
builder.RegisterType<EFUnitOfWork>().As<IEFUnitOfWork>().InstancePerLifetimeScope();
public class ProcessHandler : AsyncRequestHandler<IntermediateDocument.Command>
{
IMediator _mediator;
Func<Owned<IEFUnitOfWork>> _uow;
ILifetimeScope _scope;
public ProcessHandler(
ILifetimeScope scope,
Func<Owned<IEFUnitOfWork>> uow,
IMediator mediator)
{
_mediator = mediator;
_scope = scope;
_uow = uow;
}
protected async override Task Handle(Command request, CancellationToken cancellationToken)
{
foreach (var transaction in request.Transactions)
{
using (var scope = _scope.BeginLifetimeScope("custom"))
{
using (var uo = _uow())
{
await uo.Value.Execute(async () =>
{
await _mediator.Send(new NestedHandlerGetBySwitch.Command(transaction));
});
}
}
}
}
}
the above one is the process handler
public class NestedHandler1 : AsyncRequestHandler<NestedHandler.Command>
{
IMediator _mediator;
IEFUnitOfWork _uow;
public NestedHandler1(
IEFUnitOfWork uow,
IMediator mediator)
{
_mediator = mediator;
_uow = uow;
}
protected async override Task Handle(Command request, CancellationToken cancellationToken)
{
_uow.Repository.Add(request);
}
}
the above one is an example of nested handler.
I want the same _uow instance from processhandler.
EFUNitOFWork looks like
public class EfUnitOfWork : IEFUnitOfWork {
private DbContext _context;
ABCRepository aBCRepository;
public ABCRepository ABCRepository { get {
return aBCRepository = aBCRepository ?? new ABCRepository(_context);
} }
public EfUnitOfWork(DbContext context)
{
_context = context;
}
public Task Add(Entity entity) {
await _context.AddAsync(entity);
}
}
what am i doing wrong ?
Thankyou.
IMediator is asking AutoFac to create an instance of NestedHandler1, so it is going to have the same lifetime scope as IMediator.
One way of solving it is to resolve IMediator from the "custom" lifetime scope and use that one instead of injecting it in the constructor, and make sure that the UnitOfWork is properly registered in this scope:
using (var uo = _uow())
{
using (var scope = _scope.BeginLifetimeScope("custom", x => x.RegisterInstance(uo.Value))
{
var mediator = scope.Resolve<IMediator>();
await uo.Value.Execute(async () =>
{
await mediator.Send(new NestedHandlerGetBySwitch.Command(transaction));
});
}
}
You have a bit of a mess between UnitsOfWork, Mediators and stuff.
Let's keep things simple and deduce the implementation from the requirements.
You need to have a single DbContext shared by multiple components.
A single request could process multiple operations, by multiple handlers.
Given this two facts, we can infer that we need two distinct lifetime scopes:
the first to share the DbContext (we will call this "UnitOfWork"), and the second that corresponds to each
and every operation (let's call this "Operation").
The handling of this structure will be handled like so:
public class ProcessHandler : AsyncRequestHandler<IntermediateDocument.Command>
{
// ...ctor
protected async override Task Handle(Command request, CancellationToken cancellationToken)
{
// inside this using every component asking for an
// IEFUnitOfWork will get the same instance
using (var unitOfWorkScope = _scope.BeginLifetimeScope("UnitOfWork"))
{
foreach (var transaction in request.Transactions)
{
// we don't need this inner scope to be tagged, AFAICT
// so probably "Operation" could be omitted.
using (var scope = unitOfWorkScope.BeginLifetimeScope("Operation"))
{
// I'm not sure what a "mediator" is, I'm just copying the example code
var mediator = scope.Resolve<IMediator>();
await mediator.Send(...do something with transaction);
} // here mediator will be disposed, once for each transaction instance
}
} // here everything resolved inside unitOfWorkScope will be disposed (and possibly committed).
}
}
The dbContext must be registered as
builder.RegisterType<EFUnitOfWork>().As<IEFUnitOfWork>().InstancePerMatchingLifetimeScope("UnitOfWork");
Quite possibly you don't need the IEFUnitOfWork, but you can simply share the DbContext, registering
it in the UnitOfWork scope. In other words, the tagged scope of Autofac could replace your
class entirely, AFAICT.
Reference to the Autofac documentation:
https://autofac.readthedocs.io/en/latest/lifetime/instance-scope.html#instance-per-matching-lifetime-scope

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.

Categories