I am working with a WPF based application and using Autofac to resolve the dependency of DbContext of Entityframework. I used the below code to register my data module.
public class DataModule : Module
{
protected override void Load(ContainerBuilder builder)
{
builder.RegisterType<DataContext>()
.As<IDbContext>()
.WithParameter("nameOrConnectionString", "DefaultConnectionString")
.InstancePerLifetimeScope();
builder.RegisterGeneric(typeof(Repository<>))
.As(typeof(IRepository<>))
.InstancePerLifetimeScope();
}
}
This works fine while using in normal scenario but while using TPL, due to simultaneous calls to repository, it creates error stating that "ExecuteReader requires an open and available Connection. The connection's current state is open."
In web application, this can be resolved using InstancePerRequest to resolve dependency per request but in WPF I need to resolve this dependency per Thread request. Is there any way out for this?
I have review InstancePerRequest summary or autofac and it states that this method is used for Web request only:
// Summary:
// Share one instance of the component within the context of a single web/HTTP/API
// request. Only available for integration that supports per-request dependencies
// (e.g., MVC, Web API, web forms, etc.).
Update:
This is a simple async method that I used to get the data:
private async void OnLoadClientDetail()
{
long clientId = SelectedClient != null ? SelectedClient.Id : 0;
var listOfCollection = await _collectionService.GetCollectedCollectionAsync(clientId);
CollectionList = new ObservableCollection<CollectedCollection>(listOfCollection);
}
Here OnLoadClientDetail is bound to selection change event of a combobox. When user change the selection frequently then this method will be called multiple times. The _collectionService is injected in the viewmodel and has InstancePerLifetimeScope define. So how can I get different scope for all this calls?
As far as I can see, you share the _collectionService instance across the different event handlers by injecting it by Constructor Injection.
It probably better to use Method Injection here, so you'll get the instance per call, as you need, resolving it before method:
builder.Register(c =>
{
var result = new MyObjectType();
var dep = c.Resolve<TheDependency>();
result.SetTheDependency(dep);
return result;
});
Related
I am trying to find a way to inject a dependency in Startup.cs, for a aspnet5 application. I am aware of the following previous question, but hopefully I can expand on my particular requirements:
Aspnet core 5.0 inject dependency in startup.cs constructor
I initially needed a way to fire a custom method after OnSignIn with MS Identity Platform (IP) within my app. After posting the following questions, I was quickly pointed in the right direction:
How to fire a custom method after OnSignIn with MS Identity Platform
In short, during ConfigureServices in StartUp.cs, I needed to configure the IP middleware service, to add my own methods to some of its available events. Works a treat!
So I initially tried:
services.Configure<OpenIdConnectOptions>(OpenIdConnectDefaults.AuthenticationScheme, options =>
options.Events = new OpenIdConnectEvents
{
OnTicketReceived = async ctex =>
{
// Blah
},
});
As I say, this works great. However, to do anything serious, I need access to my existing code and the DI magic that goes with it. This is where I a hitting this problem. I need my custom logic that requires DI, during ConfigureServices, before I have configured the services for DI.
On the same post, someone pointed out that you can wrap up the configuration, and essentially inject it back in, so you can get DI back. Great! But for some reason, I can only inject the handler, either as a Singleton, or Transient. Not Scoped. I get to some extent why it can't be scoped (if it is has a dependency of its own on a transient service), but then are why both extremes ok? Why is Singleton OK? Why is Transient? It just so happens, but my DI requirements are that I would need to inject scoped services, as that is what I need. I need some of the data to persist across instances, but I can't have a single instances shared across the whole application/user base.
So then I tried:
public class AzureAdOpendIdHandler : IConfigureNamedOptions<OpenIdConnectOptions>
{
public AzureAdOpendIdHandler(Authentication.AuthenticationManager authenticationManager)
{
AuthenticationManager = authenticationManager;
}
public Authentication.AuthenticationManager AuthenticationManager { get; }
public void Configure(string name, OpenIdConnectOptions options)
{
options.Events = new OpenIdConnectEvents
{
OnTicketReceived = context =>
{
//Blah
return Task.CompletedTask;
},
};
}
}
Then called in StartUp.cs like:
services.AddScoped<Authentication.IAuthenticationManager, Authentication.AuthenticationManager>();
services.AddSingleton<IConfigureOptions<OpenIdConnectOptions>, AzureAdOpendIdHandler>();
Again, the handler works fine, and everything fires, as long as I don't try and pass "AuthenticationManager" within the constructor. I get an error saying that I can't inject a scoped service into a singleton service.
I keep getting within spitting distance of doing what I need, but there is always another block in the way.
In summary:
To override/extend MS Identity Platform, I need to make changes in ConfigureServices() in StartUp.cs
These changes require my classes to be available via DI.
The DI must allow me to pass them as scoped
So far, I can only meet the first two requirements, I can not find a way to satisfy all three.
My end requirement is to be able to add a call to my AuthenticationManager class from within the following OnTicketReceived Event:
services.Configure<OpenIdConnectOptions>(OpenIdConnectDefaults.AuthenticationScheme, options =>
options.Events = new OpenIdConnectEvents
{
OnTicketReceived = async ctex =>
{
//use my AuthenticationManager class!!
},
});
I have tried the direct method, wrapping things up in a handler and injecting, but DI seems to be getting in the way now.
Any help, would be gratefully received.
I'm registering a service as a singleton in .NET Core. Yet I'm seeing the constructor for the singleton called multiple times.
services.AddSingleton<DbAuthorizationOptions, ContextAuthorizationOptions>();
My context authorization options is just Dictionary of Entity Types to IValidators, The context authorization options are passed into the DBContext, to automatically run validations.
During the registration of my services, I also register dynamic Validators with my container registered in DI.
var useDynamicValidator = serviceOption.ValidatorOptions != null;
if(useDynamicValidator)
{
//TODO: Extract this to before the register service no sense in building the provider each time
//TODO: Make this cleaner don't be dependent on Authorization options
var provider = services.BuildServiceProvider();
var authOptions = provider.GetService<DbAuthorizationOptions>();
var validator = BuildDynamicValidatorFactory(serviceOption).Invoke(provider, null);
authOptions.ValidatorOptions.AddValidatorForSet(validator);
}
I notice that when I call GetService on the provider I receive a new singleton instead of the existing one. Does building the provider create a new container so all of the services get re-registered?
If so, How can I call a method to register my dynamic validators in the singleton container with the existing IServiceProvider, is there a way to invoke some registration once after the service container is built?
Does building the provider create a new container so all of the services get reregistered?
Yes. See the source code.
If so, How can I call a method to register my dynamic validators in the singleton container with the existing IServiceProvider, is there a way to invoke some registration once after the servicecontainer is built?
I'm not really understanding why this is a problem. You should be registering all of your services one time at application startup in the Composition Root.
The DI container is then responsible for resolving the object graphs of the application. The application itself shouldn't have a dependency on it, nor be required to update it.
You should be injecting DbAuthorizationOptions in the place where you need to use it.
public class Foo : IFoo
{
private readonly DbAuthorizationOptions authOptions;
public Foo(DbAuthorizationOptions authOptions) // <-- Inject parameters
{
this.authOptions = authOptions ??
throw new ArgumentNullException(nameof(authOptions));
}
public void DoSomething()
{
// TODO: Inject the type that has the BuildDynamicValidatorFactory
// method and the serviceOption (whatever type that is) here
// either as a method parameter of this method, or a constructor
// parameter of this class.
var validator = BuildDynamicValidatorFactory(serviceOption).Invoke(provider, null);
// Now we have an instance of authOptions that can be used
authOptions.ValidatorOptions.AddValidatorForSet(validator);
}
}
Note that the DI container automatically provides the DbAuthorizationOptions if injected into another type that is also resolved through DI (such as a controller or filter).
NOTE: It isn't very clear from your question where you need to do this. You mention that you want it to happen once, which usually means to put it at application startup. But users cannot interact with code that runs at startup. So, maybe you could use a filter. It really all depends on where in the lifecycle of the application it has to happen.
You can declare a dependency on IServiceProvider -- don't build it, inject it.
public class SomeController
{
DbAuthorizationOptions authOptions;
public SomeController(IServiceProvider provider)
{
authOptions = provider.GetSerivce<DbAuthorizationOptions>();
}
}
But this is the service locator anti-pattern. As I commented on NightOwl888's post after you gave more details, a factory is probably a better approach.
The simple injector documentation provides great examples on how to setup the container for WebRequest, Web API, WCF, ... but the examples are specific to one technology/lifestyle at a time. Our web application uses most of them together!
It is not clear to me how to configure the container to work with several lifestyles.
Let's say I have a MVC project with Web API. I have the following objects:
MyDbContext : My entity code first db context
IMyDataProvider implemented by MyDataProvider : Contains query logic and uses MyDbContext
MyController : MVC controller that uses IMyDataProvider
MyApiController : WebApi controller that uses IMyDataProvider
Should I create and configure one container for each type of lifestyle ?
When I register everything with RegisterPerWebRequest<T> is works in both types of controllers. Is this safe ? Or will I run into trouble when using async/await in a Web API controller?
What is the best configuration when I have both MVC and Web API controllers who get injected the same instances ?
Should I use a hybrid lifestyle ?
Now to complicate things... our application also uses background tasks and SignalR.
Both of these will sometimes occur outside of a WebRequest and need access to the same objects as described above.
The best solution would be to use a Lifetime scope ?
Would I need to create a new container for that lifestyle? or can I reuse/reconfigure my MVC/Web API container ?
Is there a triple lifestyle?
I have to say, I stumble on a similar scenario some time ago, I ended up by sharing my configuration over my web API and signalR, but you need to implement a custom lifestyle for signalR since it's not based on web request.
specially in signalR you'll find some issues handling per-web-request dependencies in a Hub some of them are going to be null like httpContext.Current among others.
The solution:
You need a hybrid lifestyle between WebRequestLifestlye and either Lifestyle.Transient, Lifestyle.Singleton, or LifetimeScopeLifestyle. I ended up I finished using the decorator pattern, you may read this post and this other post.
my decorator
public class CommandLifetimeScopeDecorator<T> : ICommandHandler<T>
{
private readonly Func<ICommandHandler<T>> _handlerFactory;
private readonly Container _container;
public CommandLifetimeScopeDecorator(
Func<ICommandHandler<T>> handlerFactory, Container container)
{
_handlerFactory = handlerFactory;
_container = container;
}
public void Handle(T command)
{
using (_container.BeginLifetimeScope())
{
var handler = _handlerFactory(); // resolve scoped dependencies
handler.Handle(command);
}
}
}
public interface ICommandHandler<in T>
{
void Handle(T command);
}
I managed the dependencies using a hub activator for signalR
public class MyHubActivator : IHubActivator
{
private readonly Container _container;
public MyHubActivator(Container container)
{
_container = container;
}
public IHub Create(HubDescriptor descriptor)
{
return _container.GetInstance(descriptor.HubType) as IHub;
}
}
a composite root file which is where you are going to handle your dependencies
public CompositRoot(Container container)
{
_container = container;
}
public container Configure()
{
// _container.Registerall container dependencies
return _container;
}
then share your composite root configuration when you are bootstrapping your app
var compositRoot = new CompositRoot(simpleInjector.Container); //simple injector instance
compositRoot.Configure();
For signalR
GlobalHost.DependencyResolver.Register(typeof(IHubActivator), () => new MyHubActivator(compositRoot));
and you may reuse your configuration among other projects!
my two cents
hope that helps!
Usually you don't need to have one container per lifestyle; In general you want to have one container instance per AppDomain. However, mixing Web API in the same project with MVC is from an architectural point of view a horrible idea IMO (as explained here, here, and here). So in case you are separating those parts into their own architectural blocks, you will already have less problems already.
But in case you are running MVC and Web API in the same project, this basically means that you will always be using Web API. The WebApiRequestLifestyle was explicitly built to work:
well both inside and outside of IIS. i.e. It can function in a
self-hosted Web API project where there is no HttpContext.Current.
(source)
In general, it is safe to use the WebRequestLifestyle in case you are only running in IIS when you have no intention to spin of parallel operations using ConfigureAwait(false) (which should be really rare IMO) as explained here.
So in the case you are still mixing Web API with MVC in the same project, there's no reason to use a hybrid lifestyle; you can simply use the same lifestyle. For doing background processing you might however need to build a hybrid lifestyle, but it every scenario needs a different hybrid. However, hybrids can be stacked up and you can easily create a 'triple lifestyle' if needed.
Since you want to do background processing with SignalR, you need to decide in what type of scoped lifestyle to run those background operations. The most obvious lifestyle is the LifetimeScopeLifestyle and this means you should make your scoped registrations using the following scoped lifestyle:
var hybridLifestyle = Lifestyle.CreateHybrid(
lifestyleSelector: () => HttpContext.Current != null,
trueLifestyle: new WebRequestLifestyle(),
falseLifestyle: new LifetimeScopeLifestyle());
A lifetime scope however needs to be started explicitly (as were the web request scope gets started implicitly for you if you include the SimpleInjector.Integration.Web.dll in your web application). How to do this depends on your design, but this q/a about SignalR might point you in the right direction.
I'm trying to move from Ninject to Simple Injector but I'm experiencing an odd issue when trying to duplicate functionality that worked with Ninject.
In Ninject I had a service which contained:
private readonly ICollection<Message> messages;
This service was registered as
Bind<INotificationService>().To<NotificationService>()
.InRequestScope();
This service allowed messages (UI and error) to be passed back to the MVC site.
This service was injected into an ActionFilterAttribute:
kernel.BindFilter<CriticalErrorAttribute>(FilterScope.Last, 1)
.When((context, ad) =>
!string.IsNullOrEmpty(ad.ActionName) &&
ad.ControllerDescriptor.ControllerName.ToLower() != "navigation");
and used within OnActionExecuted.
Because the service was registered to Ninject with InRequestScope, any items pushed to the message queue were available in the Actionfiter. This allowed for a redirect to an error page (displaying critical errors) if necessary.
I've tried to duplicate this with simpleinjector:
container.RegisterPerWebRequest<INotificationService, NotificationService>();
container.RegisterInitializer<CriticalErrorAttribute>(handler =>
{
handler.NotificationService =
container.GetInstance<INotificationService>();
});
The injection is working fine, but even though the message collection contains messages prior to entering the ActionFilter, once in the filter the message collection is empty. It's like the RegisterPerWebRequest is being ignored.
Any help in solving this issues would be appreciated.
UPDATE:
In Simple Injector 2.5 a new RegisterMvcIntegratedFilterProvider extension method has been added to the MVC Integration package that replaces the old RegisterMvcAttributeFilterProvider. This new RegisterMvcIntegratedFilterProvider contains the behavior of the SimpleInjectorFilterAttributeFilterProvider that is given below and allows better integration of attributes into the Simple Injector pipeline. This does mean however that by default, no properties are injected, but this can extended by implementing a custom IPropertySelectionBehavior. The use of the new RegisterMvcIntegratedFilterProvider is adviced over the old RegisterMvcAttributeFilterProvider method, which will be marked [Obsolete] in a future release.
When using the RegisterMvcAttributeFilterProvider extension method, Simple Injector will not call any registered initializer on MVC attributes. If you set a break point inside the anonymous delegate that injects the NotificationService you'll see it's never hit.
Simple Injector does however call the container.InjectProperties method on MVC attributes, but InjectProperties does implicit property injection, which means that it tries to inject all public properties on a type, but skips it if the property can't be injected (for what ever reason).
I bet the CriticalErrorAttribute.NotificationService property has a type of NotificationService instead of INotificationService. Since you didn't register NotificationService explicitly, the container will create a transient instance for you, which means you'll get a different instance for the CriticalErrorAttribute than the rest of the application is getting.
Quick fix: change the property type to INotificationService.
To be honest, I regret ever implemented the MVC integration package for Simple Injector to use the InjectProperties method. Implicit Property injection is very evil, because it doesn't fail fast when there's a misconfiguration and I'm even thinking about removing support for InjectProperties in the future. The problem is however that many developers are depending on InjectProperties. Either directly by calling it, or indirectly by letting the container inject properties on MVC attributes.
InjectProperties does not run any initializer. That's by design, and there are other constructs that allow running the full initialization process on objects that are not created by the container. Problem is however, that adding this could break existing clients, since this could result in properties being injected multiple times.
In your case, I suggest a different solution:
Prevent calling container.RegisterMvcAttributeFilterProvider() in the startup path of your application. This will register a special FilterAttributeFilterProvider that calls InjectProperties internally. You don't want to use implicit property injection, you want a more explicit (and complete) behavior. Instead register the following class:
internal sealed class SimpleInjectorFilterAttributeFilterProvider
: FilterAttributeFilterProvider
{
private readonly ConcurrentDictionary<Type, Registration> registrations =
new ConcurrentDictionary<Type, Registration>();
private readonly Func<Type, Registration> registrationFactory;
public SimpleInjectorFilterAttributeFilterProvider(Container container)
: base(false)
{
this.registrationFactory = type =>
Lifestyle.Transient.CreateRegistration(type, container);
}
public override IEnumerable<Filter> GetFilters(
ControllerContext context,
ActionDescriptor descriptor)
{
var filters = base.GetFilters(context, descriptor).ToArray();
foreach (var filter in filters)
{
object instance = filter.Instance;
var registration = registrations.GetOrAdd(
instance.GetType(), this.registrationFactory);
registration.InitializeInstance(instance);
}
return filters;
}
}
You can use the following code to register this custom provider:
var filterProvider =
new SimpleInjectorFilterAttributeFilterProvider(container);
container.RegisterSingle<IFilterProvider>(filterProvider);
var providers = FilterProviders.Providers
.OfType<FilterAttributeFilterProvider>().ToList();
providers.ForEach(provider => FilterProviders.Providers.Remove(provider));
FilterProviders.Providers.Add(filterProvider);
This custom SimpleInjectorFilterAttributeFilterProvider calls the Registration.InitializeInstance method. This method allows initialization a type that is already created and will initialize it by (among other things) calling the type initializer delegates.
For more information about working with attributes, please read the following discussion.
I want to inject an instance into structuremap on the fly (i.e. outside of a registry/configuration) that lives for the life of the request.
Currently I'm doing this in the HandleBeginRequest event of an IHttpModule:
container.Configure(x => x.For<IMyClass>()
.LifecycleIs(Lifecycles.GetLifecycle(InstanceScope.PerRequest))
.Use(new MyClass()));
However, if at some point in the application's life I do:
ObjectFactory.WhatDoIHave();
I see as many configured instances for IMyClass as there have been requests (or at least a significant amount).
Thinking about it, this sort of makes sense given the code I have.
Is there a better way to inject an instance into the container just for the life of the current request in a way that doesn't pollute the whole container?
Thanks
Your problem is that you're registering the type in the container once per request, which is building up on the registrations. Configuring the container should ideally be made once in the application's lifecycle - typically in the Application_Start event for web applications.
Structuremap allows you to specify a creational function that is invoked upon creating the object, which will let you configure advanced object creation steps.
Instead of your current call to Configure in the Begin_Request event, stick the following in the container configuration during Application_Start.
For<IMyClass>().HttpContextScoped().Use(() => new MyClass());
Notice the lambda in the Use method. The lambda can contain any logic needed in order to create the object and it will be invoked one per lifecycle (per request in the case of HttpContext lifecycle).
I went with this in the end
For<IRequestContextStorage>()
.HybridHttpOrThreadLocalScoped()
.Use<RequestContextStorage>();
For<MyClass>()
.Use(c => c.GetInstance<IRequestContextStorage>().Get<MyClass>());
...
public class RequestContextStorage : IRequestContextStorage
{
readonly IDictionary<Type, object> hash;
public RequestContextStorage()
{
this.hash = new Dictionary<Type, object>();
}
public T Get<T>() where T : class
{
if(this.hash.ContainsKey(typeof(T)))
return this.hash[typeof (T)] as T;
return null;
}
public void Set<T>(T instance)
{
this.hash[typeof (T)] = instance;
}
}
...
static void HandleBeginRequest(object sender, EventArgs e) {
ObjectFactory.Get<IRequestContextStore>().Set(new MyClass());
}
If you only have one container, and you have multiple requests, you will run into this problem. I would suggest managing the per request instances yourself by storing them in HttpContext.Items.
If you want to be able to access it through the container, create a gateway class that holds no state and pulls your per request dependency out of HttpContext for you. Register that in your container, and update dependencies on the per request object to you the gateway.
Update
I can't believe I overlooked this before, what you really want is to use HttpContextLifecycle, which will cache a given instance in the HttpContext.Items collection, where it will be available throughout your request. You will still have multiple instances active during concurrent requests, but StructureMap can figure out which one to return based on HttpContext.Current.