Is there a way to define a scope for a specific lifestyle? I am attempting to implement my own scope that I want to persist across an application, but internally I also create another scope, and then a request to GetInstance returns the inner scoped instance instead.
I thought if I could define my lifestyle as:
public class MyScopedLifestyle : ExecutionContextScopeLifestyle
{
public MyScopedLifestyle(bool disposeInstanceWhenScopeEnds)
: base("MyScopedLifestyle", disposeInstanceWhenScopeEnds)
{
}
protected override int Length
{
get
{
return 100;
}
}
}
And my usage is:
var container = new Container();
container.Register<IRequestData, RequestData>(new MyScopedLifestyle());
// i had hoped I could say
// container.BeginExecutionContextScope(MyScopedLifestyle)
// or something similar
// this is controlled by me
using (var scope1 = container.BeginExecutionContextScope())
{
// do some stuff
container.GetInstance<IRequestData>().RequestMarket = "en-US";
// this is done via the webapi execution scope (using simpleinjector dependency resolver)
using (var scope2 = container.BeginExecutionContextScope())
{
Assert.Equal("en-US", container.GetInstance<IRequestData>().RequestMarket); // false
}
}
But I'm unsure how to utilize my custom lifestyle when creating the inner execution scope.
What I really want to happen, is that my instance of IRequestData used in scope1, is the same instance of IRequestData inside of scope2. Is this something I can achieve with SimpleInjector?
Edit
I removed the fact that I'm attempting to create an instance of an object per OWIN request, rather than per WebAPI request. Ideally I'm attempting to create:
container.RegisterOwinRequest<IRequestData, RequestData>();
So that when I resolve IFoo anywhere within my pipeline (be it an OWIN middleware, or in the WebAPI part, the same instance is returned for a particular request).
Edit 2
Swapped our IFoo/Foo/MyProperty for better names.
What you're trying to accomplish with a custom lifestyle is absolutely possible, but might not be that easy, because you will have to store that scope somewhere (probably in the CallContext) and need to create a BeginMyCustomScope method that creates a new scope and have a custom Scope implementation that removes itself from the CallContext when Dispose is called. I think this is too much work and too much complexity.
The problem exists because during the time you want to set the RequestMarket property, there is no Web API request scope started. The way to usually force such scope to be started is to call the GetDependencyScope method on the HttpRequestMessage:
message.GetDependencyScope();
Right after that you can resolve the IRequestData and it works as expected:
container.GetInstance<IRequestData>().RequestMarket = "en-US";
I'm unsure however, whether the HttpRequestMessage is available at that point in time, so if not, I think working with a DelegatingHandler as you expressed in the comments is a good alternative.
In the past, a good way to communicate data across the callstack was using thread-specific variables, but that obviously fails when using async/await models as with Web API and OWIN. So the new way to do this is using the CallContext. So instead of using a DelegatingHandler, you might be able to do something like this:
container.RegisterInitializer<IRequestData>(data =>
data.RequestMarket = (string)CallContext.LogicalGetData("RequestMarketKey"));
And when the OWIN request starts, you do this:
CallContext.LogicalSetData("RequestMarketKey", "en-US");
Related
Perhaps I'm just using the wrong terms while searching, but I haven't found any solid guidance around how to do what I'm seeking to do.
All the guidance around DI registration follows something like the following:
builder.Services.AddSingleton<MyService>(() => new MyService("connectionString"));
But this seems too simple for me to use over here in the real world. I don't store my various credentials in my applications, but rather put them somewhere else like Azure Key Vault or authenticate using a managed identity that itself retrieves connection strings and keys.
This introduces the need then to access the credentials/connection string first, which increasingly is exposed only as an asynchronous operation and introduces the problem I regularly face: namely, asynchronous registration isn't a thing.
I could register a service that itself retrieves and exposes the credential in an async method, but now every downstream service is going to need to know about that method in order to utilize it - I can't simply abstract it away in a DI registration.
I could just use .Result or Wait(), but there's plenty of solid guidance that suggests this shouldn't be done for deadlocking reasons. Because this code may be intended for a library that's consumed by an app with a UI, that's a no-go.
So the question is: When I'm unable to synchronously provide my credentials, how do I register my services?
Real-world example
For example, let's say I've got a web app that needs to access Cosmos DB, but via a managed identity, following the instructions here. I need to store some information about the Cosmos DB instance which means a dependency on IConfiguration and I'd like to use a singleton HttpClient to retrieve the necessary keys.
I want to put this into a separate service responsible for setting up the Cosmos DB client so that downstream usages can just inject the CosmosClient, so my class looks like:
public class CosmosKeyService
{
private readonly MyCosmosOptions _cosmosOptions;
private readonly HttpClient _http;
public CosmosKeyService(IOptions<MyCosmosOptions> options, HttpClient http)
{
_cosmosOptions = options.Value;
_http = http;
}
private async Task<string> GetCosmosKey()
{
//Follow instructions at https://learn.microsoft.com/en-us/azure/cosmos-db/managed-identity-based-authentication#programmatically-access-the-azure-cosmos-db-keys
//...
var keys = await result.Content.ReadFromJsonAsync<CosmosKeys>();
return keys.PrimaryMasterKey;
}
public async Task<CosmosClient> GetCosmosClient()
{
var key = await GetCosmosKey();
return new CosmosClient(_cosmosOptions.CosmosDbEndpoint, key);
}
}
To support the DI used in this class, my registration then looks like:
builder.Services.Configure<MyCosmosOptions>(builder.Configuration.GetSection("cosmosdb"));
builder.Services.AddSingleton<HttpClient>();
And of course I'm going to need to register this service:
builder.Services.AddSingleton<CosmosKeyService>();
But now I'd also like to register the CosmosClient as created by the method in that service and this is where I start getting confused about the best way forward.
I can't retrieve an instance of the CosmosKeyService from the builder because I haven't yet built it, and after I do, I can't then register new services.
I can't use async methods in the registration itself or I could easily do something like:
builder.Services.AddSingleton<CosmosClient>(async services => {
var keyService = services.GetService<CosmosKeyService>();
return await keyService.GetCosmosClient();
});
...and downstream services could simply inject CosmosClient in their various constructors.
Again, any downstream consumer can just inject a CosmosKeyService, but now they're all going to have to "remember" to call the initialization method first so they can retrieve the CosmosClient and utilize it. I'd rather that be handled in registration so that 1) this initialization is hidden and centrally located and 2) the CosmosClient is truly a singleton and not just an artifact of every utilization.
I could create another intermediate service that injects this Key resolver service and retrieve the keys, but it too will need to have this async method that retrieves the keys since I can't just hide that initialization in a registration somewhere (for lack of async support).
For example, I could make another service:
public class CosmosBuilder
{
private readonly CosmosKeyService _keySvc;
public CosmosBuilder(CosmosKeyService keySvc)
{
_keySvc = keySvc;
}
public async Task<CosmosClient> GetCosmosClient()
{
return async _keySvc.GetCosmosClient();
}
}
But this ultimately still requires a downstream service to inject this service and call that initialization method and if that's necessary, I might as well just stick with injecting the CosmosKeyService and call the method there.
What I'd ideally like to see is some way to hide any async initialization in the registration so that downstream consumers can simply inject CosmosClient and it works, but it's beyond me how that's intended to happen. Can anyone shed some light on this?
Edit to address comment:
I don't want to comment on a 4-year old answer, but the issue I assert with the accepted answer boils down to this part:
Move [initialization] into the Composition Root. At that point, you can create an initialize those classes before registering them in the container and feed those initialized classes into the container as part of registrations.
That's all well and good except:
I only get to "build" my container a single time. I can't build it, then utilize the registrations to accomplish the initialization, then append still more registrations to it for later use.
In my example above, I explicitly utilize elements registered in DI by ASP.NET Core itself (namely IConfiguration), so there's simply no way to even access these except via DI (which, per #1, precludes me from being able to initialize and later supplement my registrations with more implementations).
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;
});
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 am using a framework that allow me to intercept in some entry points.
The framework scope is not Web Request, not thread and not transient, its something like thread based, but i saw a lot of places with thread reuse.
So i need a custom scope, where i say where to start and where to end the scope.
Since I have a lot of dependencies, most of them are defined in static contractor, because they are stateless.
I have one dependency that actually need to be injected on every framework interception.
This is the interception method, and how I do the injection (I am not calling this method, the framework does). So what i need here is to inject the AppContext and make sure that Castle always resolve me the correct context (within the scope)
public void Execute(AppContext context)
{
using (var s = CastleContainer.Container.BeginScope())
{
CastleContainer.Container.Register(Component.For<AppContext>().LifestyleScoped().Instance(context));
var logic = CastleContainer.Container.Resolve<ICustomerLogic>();
// begin invocation
}
}
ICustomerLogic has dependency in ICustomreDal and ICustomreDal has dependency in AppContext.
So when I resolve Resolve<ICustomerLogic>() I want to be sure that ICustomreDal has the current AppContext.
ICustomerLogic and registered as singleton, and ICustomreDal registered as transient.
The first execution works fine, the second execution I get the error:
AppContext could not be registered. There is already a component with
that name. Did you want to modify the existing component instead? If
not, make sure you specify a unique name.
Isn't castle suppose to do the scope segmentation so each scope has its own dependencies?
What am I doing wrong?
Please note that we are talking about 50 executions in a second.
The BeginScope is not about registration, it is only about component resolving. It will make sure that any component that is created within the using statment, with lifestyle Scoped gets released (disposed if necessary) when the using statements end. It does not unregister components that are registered in the block. In general it is a bad idea to register your components in multiple places. Only register components at the startup of your application.
I've been struggling a lot with something similair and finally used this workaround with I was not totally happy with but if there is anyone with a better solution I would love to hear. Adapted to your situation it would look something like this:
in your registration code use:
Component.For<ICustomerLogic>().ImplementedBy<CustomerLogic>().LifestyleScoped
Component.For<AppContext >().UsingFactoryMethod(() => (AppContext)Thread.GetNamedDataSlot("context")).LifestyleTransient() // or scoped
adapt your Execute function to:
public void Execute(AppContext context)
{
using (var s = CastleContainer.Container.BeginScope())
{
Thread.SetData(Thread.GetNamedDataSlot("context"), context);
var logic = CastleContainer.Container.Resolve<ICustomerLogic>();
Thread.SetData(Thread.GetNamedDataSlot("context"), null);
// begin invocation
}
}
Goodluck,
Marwijn.
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.