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.
Related
I'm building an application that performs actions initiated by a user and one particular class has dependencies on things I can wire up in DI such as an ILogger instance as well as an HttpClient in addition to runtime arguments that identify the user and the instance of the action (mostly to be used while logging to help with debugging).
The trouble I have is that I'm not entirely sure how to inject this class into the other classes that need it as a result of the runtime dependencies.
Here's a simplified example of one of my classes:
public class Dependency : IDependency
{
private readonly HttpClient httpClient;
private readonly ILogger<Dependency> logger;
private readonly RuntimeDeps runtimeDeps
public Dependency(
ILogger<Dependency> logger,
HttpClient httpClient,
RuntimeDeps runtimeDeps)
{
// set private fields
}
public Result DoStuff()
{
// use Http client to talk to external API
// something fails so log the failure and some helpful info
logger.log($"{runtimeDeps.InstanceId} failed. " +
"Initiated by {runtimeDeps.UserName}");
}
}
This feels like it requires a factory to create but then is it best to request the HttpClient and Logger in the factory method or declare it as a dependency of the factory? If the latter, I presume the factory would have to be registered as a transient or as a scoped resource since registering it as a singleton would result in a captive dependency (I think).
Any suggestions on redesigns are also welcome if this is a symptom of a poor design. I'd love to implement Mark Seeman's Pure DI to get some more assistance from the compiler but I don't know if that's possible in Azure functions.
A transient factory with the transient dependencies injected into the constructor and the runtime dependencies as parameters of the Create method will work fine.
DI is baked into the Azure Functions library in the sense that parameters are injected into the trigger methods, but beyond these you should be able to use Pure DI to manage your own dependencies by calling into some composition root helper class from the trigger function which knows how to build your dependency graph in a pure manner.
Instead of requiring runtime data during the construction of a component, it's better to let runtime data flow through method calls on an initialized object graph by either:
passing runtime data through method calls of the API or
retrieving runtime data from specific abstractions that allow resolving runtime data.
I formalized this in 2015 in this blog post, which I referred to in the comments.
After reading your additional comments, I came to the conclusion that in your case option 2 is most suited, as the data you are sending is likely an implementation detail to the component, and should not be part of the public API.
In that case, you can redesign your component as follows:
public class Dependency : IDependency
{
public Dependency(
ILogger<Dependency> logger,
HttpClient httpClient,
IRuntimeDepsProvider provider) ...
public Result DoStuff()
{
// use Http client to talk to external API
// something fails so log the failure and some helpful info
logger.log($"{provider.InstanceId} failed. " +
$"Initiated by {provider.UserName}");
}
}
IRuntimeDepsProvider is an abstraction that hides the retrieval and storage of runtime data. This gives you the ability to postpone the decision to either use a Closure Composition Model or an Ambient Composition Model until the Last Responsible Moment.
Using the IRuntimeDepsProvider abstraction, you can chose to set the incoming runtime values after the object graph is constructed. For instance:
public class MyFunction
{
// Notice the different abstraction here
public MyFunction(
IRuntimeDepsInitializer initializer,
IHandler<Something> handler) ...
public void TheFunction(Guid instanceId, string userName, Something cmd)
{
// Setting the runtime data *after* the object graph is constructed,
initializer.SetData(instanceId, userName);
// but before the graph's public methods are invoked.
handler.Handle(cmd);
}
}
Here, a second abstraction is introduced, namely IRuntimeDepsInitializer. Now you can have one class implementing both interfaces:
public class RuntimeDepsStorage : IRuntimeDepsInitializer, IRuntimeDepsProvider
{
public Guid InstanceId { get; private set; }
public string UserName { get; private set; }
public void SetData(Guid id, string name)
{
InstanceId = id;
UserName = name;
}
}
TIP: Instead of using two interfaces, you can also use only IRuntimeDepsProvider and let MyFunction depend on the concrete RuntimeDepsStorage. Which solution is best depends on the context.
Now the main trick here is to make sure that RuntimeDepsStorage becomes a Scoped dependency, because you want to reuse it throughout a request, but not shared by multiple requests.
When applying Pure DI, this would look like this:
var storage = new RuntimeDepsStorage();
new MyFuncion(
initializer: storage,
handler: new SomethingHandler(
stuffDoer: new Dependency(
httpClient: client, // Did you notice this is a runtime dep as well?
logger: new Logger<Dependency>(),
provider: storage)))
If, on the other hand, you would be using MS.DI as your DI Container, registration would be similar to the following:
services.AddScoped(_ => new RuntimeDepsStorage());
services.AddScoped<IRuntimeDepsProvider>(
c => c.GetRequiredService<RuntimeDepsStorage>());
services.AddScoped<IRuntimeDepsInitializer>(
c => c.GetRequiredService<RuntimeDepsStorage>());
// etc, your usual registrations here
I am looking for guidance on how to correctly and safely dispose of registered singleton instances when my ASP.NET Core 2.0 app is shutting down.
According to the following document, if I register a singleton instance (via IServiceCollection) the container will never attempt to create an instance (nor will it dispose of the instance), thus I am left to dispose of these instances myself when the app shuts down.
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-2.0 (2.1 has the same guidance)
I enclose some pseudo code that illustrates what I am trying to achieve.
Note I am having to maintain a reference to IServiceCollection since the IServiceProvider provided to the OnShutDown method is a simple service locator and doesn't give me the ability to execute complex queries.
When the app shuts down I want a generic way to ensure all singleton instances are disposed. I could maintain a reference to all these singleton instances directly but this doesn't scale well.
I originally used the factory method which would ensure the DI managed the lifetime of my objects, however, the execution of the factory method happened at runtime in the pipeline of handling a request, which meant that if it threw an exception the response was 500 InternalServerError and an error was logged. By creating the object directly I am striving for faster feedback so that errors on startup lead to a automatic rollback during the deployment. This doesn't seem unreasonable to me, but then at the same time I don't to misuse the DI.
Does anyone have any suggestions how I can achieve this more elegantly?
namespace MyApp
{
public class Program
{
private static readonly CancellationTokenSource cts = new CancellationTokenSource();
protected Program()
{
}
public static int Main(string[] args)
{
Console.CancelKeyPress += OnExit;
return RunHost(configuration).GetAwaiter().GetResult();
}
protected static void OnExit(object sender, ConsoleCancelEventArgs args)
{
cts.Cancel();
}
static async Task<int> RunHost()
{
await new WebHostBuilder()
.UseStartup<Startup>()
.Build()
.RunAsync(cts.Token);
}
}
public class Startup
{
public Startup()
{
}
public void ConfigureServices(IServiceCollection services)
{
// This has been massively simplified, the actual objects I construct on the commercial app I work on are
// lot more complicated to construct and span several lines of code.
services.AddSingleton<IDisposableSingletonInstance>(new DisposableSingletonInstance());
// See the OnShutdown method below
this.serviceCollection = services;
}
public void Configure(IApplicationBuilder app)
{
var applicationLifetime = app.ApplicationServices.GetRequiredService<IApplicationLifetime>();
applicationLifetime.ApplicationStopping.Register(this.OnShutdown, app.ApplicationServices);
app.UseAuthentication();
app.UseMvc();
}
private void OnShutdown(object state)
{
var serviceProvider = (IServiceProvider)state;
var disposables = this.serviceCollection
.Where(s => s.Lifetime == ServiceLifetime.Singleton &&
s.ImplementationInstance != null &&
s.ServiceType.GetInterfaces().Contains(typeof(IDisposable)))
.Select(s => s.ImplementationInstance as IDisposable).ToList();
foreach (var disposable in disposables)
{
disposable?.Dispose();
}
}
}
}
It's the DI's job to dispose of any IDisposable objects it creates, whether transient, scoped or singleton. Don't register existing singletons unless you intend to clean them up afterwards.
In the question's code there's no reason to register an instance of DisposableSingletonInstance. It should be registered with :
services.AddSingleton<IDisposableSingletonInstance,DisposableSingletonInstance>();
When the IServiceCollection gets disposed, it will call Dispose() on all the disposable entities created by it. For web applications, that happens when RunAsync() ends;
The same holds for scoped services. In this case though, the instances will be disposed when the scope exits, eg when a request ends.
ASP.NET creates a scope for each request. If you want your service to be disposed when that request ends, you should register it with :
services.AddScoped<IDisposableSingletonInstance,DisposableSingletonInstance>();
Validation
For the latest edit :
By creating the object directly I am striving for faster feedback so that errors on startup lead to a automatic rollback during the deployment.
That's a different problem. Deployment errors are often caused by bad configuration values, unresponsive databases etc.
Validating Services
A very quick & dirty way to check would be to instantiate the singleton once all startup steps are complete with :
services.GetRequiredService<IDisposableSingletonInstance>();
Validating Configuration
Validating the configuration is more involved but not that tricky. One could use Data Annotation attributes on the configuration classes for simple rules and use the Validator class to validate them.
Another option is to create an IValidateable interface with a Validate method that has to be implemented by each configuration class. This makes discovery easy using reflection.
This article shows how the IValidator interface can be used in conjunction with an IStartupFilter to validate all configuration objects when an application starts for the first time
From the article :
public class SettingValidationStartupFilter : IStartupFilter
{
readonly IEnumerable<IValidatable> _validatableObjects;
public SettingValidationStartupFilter(IEnumerable<IValidatable> validatableObjects)
{
_validatableObjects = validatableObjects;
}
public Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next)
{
foreach (var validatableObject in _validatableObjects)
{
validatableObject.Validate();
}
//don't alter the configuration
return next;
}
}
The constructor gets all instances that implement IValidatable from the DI provider and calls Validate() on them
That's not accurate. Singletons are disposed at app shutdown, though it's kind of not actually all that relevant because when the process stops, everything goes with it anyways.
The general rule of thumb is that when using DI, you should use DI all the way down, which then means you'll almost never be disposing on your own, anywhere. It's all about ownership. When you new stuff up yourself, you're also then responsible for disposing of it. However, when using DI, the container is what's newing things up, and therefore, the container and only the container should then dispose of those things.
Thanks for the responses Panagiotis Kanavos and Chris Pratt and for helping to clarify how best to deal with this scenario. The two take away points are this:
Always strive to let the container manage the life cycle of your objects so when the app is shutdown the container will automatically dispose of all objects.
Validate all your configuration on app startup before it is consumed by objects registered in the container. This allows your app to fail fast and protects your DI from throwing exceptions when creating new objects.
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.
Working with ServiceStack I've stuck with the problem of objects lifetime management in self-hosted web application.
My requirements:
Need of per-request objects lifetime scope.
I'm using Castle Windsor IoC with implemented ServiceStack IoC adapter.
My application is self-hosted with base class AppHostHttpListenerPoolBase (ServiceStack v4)
Probably one day I want to move on IIS, thus it's must be flexible.
General problem:
Castle Windsor IoC implements its own per-request lifetime strategy but it is binded to http modules, thus it works only with IIS hosted apps. Hence, I have to implement my custom IScopeAccessor (provided by Castle Windsor) to handle objects lifetime. The problem here is in absence of hooks which I can use to bind to current request.
Given
public class MyScopeAccessor : IScopeAccessor
{
public ILifetimeScope GetScope(CreationContext context)
{
//implement it
}
}
I have to implement GetScope method.
There are two main ideas I cannot complete:
Using of [Threadstatic]
In MyScopeAccessor I just store
[ThreadStatic]
private static ILifetimeScope _currentLifetimeScope;
and create new scope after first GetScope if it's not initialzied yet.
Problems:
Hard to dispose. Best way to dispose _currentLifetimeScope is to implement custom IServiceRunner (or inherit from ServiceRunner) overriding AfterEachRequest method. But I don't exactly know if AfterEachRequest is actually executed in request thread.
Moving to IIS can cause some problems because as I know IIS doesn't guarantee unchangeable binding between theads and request contexts.
Using of IRequest instance
In MyScopeAccessor I just store
private static readonly ConcurrentDictionary<IRequest, ILifetimeScope> LifetimeScopes;
and create and dispose current lifetime scope in corresponding custom ServiceRunner methods (OnBeforeEachRequest, OnAfterEachRequest).
Problems:
I don't know how to get access to current request globally from GetScope, MyScopeAccessor knows nothing about services and requests.
Also, it is interesting if ServiceStack default Funq IoC solves this problem.
Funq does handle RequestScoped dependencies which stores Request Context dependencies in the RequestContext.Instance.Items[] dictionary.
Any disposables can be registered in RequestContext.Instance.TrackDisposable() are automatically disposed of at the end of the request.
At the end of each request AppHost.OnEndRequest() is fired which goes through and releases any dependencies stored in the RequestContext for that request.
If your Windsor ContainerAdapter implements the IRelease interface it's automatically called to release any instances which can be handled itself. Both these API's are overridable in your AppHost if you want to change the default behavior:
public virtual void OnEndRequest()
{
var disposables = RequestContext.Instance.Items.Values;
foreach (var item in disposables)
{
Release(item);
}
RequestContext.Instance.EndRequest();
}
public virtual void Release(object instance)
{
try
{
var iocAdapterReleases = Container.Adapter as IRelease;
if (iocAdapterReleases != null)
{
iocAdapterReleases.Release(instance);
}
else
{
var disposable = instance as IDisposable;
if (disposable != null)
disposable.Dispose();
}
}
catch { /*ignore*/ }
}
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.