-
-
Notifications
You must be signed in to change notification settings - Fork 837
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add an IfNotExists registration extension #469
Comments
This has been on the backlog for a while and it appears we've lost the clone. If we were to do this, I am curious how it would be intended to work. For example...
I think it could be interesting, but I can see it may also lead to a lot of complexity. Getting some clarification around it would be valuable. And, of course, if it turns out the problem is too big, it may not be worth solving, in which case it'd be nice to close the issue. It has technically been open for like three years... |
Another question: When does
Is In the former case, the first registration wouldn't run because it would see that the second registration filled the requirement. In the latter case, you'd get two copies of the registration in the container. I continue to struggle to understand how to determine "equality" in the context of A couple of possibilities I can think of: Use the new For example, we could make some extension methods to allow a registration to add to the dictionary... builder.RegisterType<First>().As<IService>().SetExists("First");
// which would be roughly equivalent to...
builder.RegisterType<First>().As<IService>();
builder.Properties["First_Exists"] = true; Then a corresponding extension for checking exists: builder.RegisterType<First>().As<IService>().IfNotExists("First");
// which would need to evaluate some sort of callback
// that roughly does...
if(!builder.Properties.ContainsKey("First_Exists"))
{
builder.RegisterType<First>().As<IService>();
} That latter example isn't exactly what it would do, but the basic equivalent. The idea being the registration callback being added would have that clause in it. Provide some sort of predicate ability. Instead of just builder.RegisterType<First>()
.As<IService>()
.IfNotExists(ctx => ctx.IsRegistered(typeof(First))); I'm not sure what would be passed into that predicate. Maybe the component registry at the time the check is occurring? This would allow the caller to determine what equality means, though it may not be as simple in usage as the properties dictionary. |
Minor progress(?) update: I spent a few hours on this one today, looking to see where/how something like this might best be implemented. It's definitely not straightforward and will likely incur some breaking API changes. What we haveWhen you register something in a When you call
var rb = RegistrationBuilder.ForType<TImplementer>();
builder.RegisterCallback(cr => RegistrationBuilder.RegisterSingleComponent(cr, rb));
return rb; Note the actual If we wanted to add a fluent mechanism for adding a predicate, something like this... builder.RegisterType<First>()
.As<IService>()
.OnlyIf(ctx => !ctx.IsRegistered(typeof(First))); ...then we'd need a way to grab that callback, the Keep in mind this gets more complex because things like assembly scanning, registration sources, and so on have different callbacks they execute to get their jobs done. We have a few options, but I'm not sure if any are terribly non-invasive. Totally open to additional ideas. Brainstorming here. Option 1: Add predicate overloads to registration methodsThis is probably the simplest thing that would work. Using builder
.RegisterType<First>(ctx => !ctx.IsRegistered(typeof(First)))
.As<IService>(); By taking the predicate into the method at the start, we can easily capture the point at which The benefit here is that it probably wouldn't break any interfaces. It'd also be pretty simple to do. The drawback is that it's a pretty ugly syntax, not fluent at all. That definitely goes against how other Autofac additions have been made. Option 2: Track callbacks made in the ContainerBuilderThis is a lot more invasive but allows for a nicer syntax. The idea with this is that callback registrations would be given individual IDs at registration time. If var rb = RegistrationBuilder.ForType<TImplementer>();
builder.RegisterCallback(cr => RegistrationBuilder.RegisterSingleComponent(cr, rb));
return rb; ...it would need to become something slightly different to allow the value to be located later: var rb = RegistrationBuilder.ForType<TImplementer>();
rb.CallbackContainer = builder.RegisterCallback(cr => RegistrationBuilder.RegisterSingleComponent(cr, rb));
return rb; The An var original = rb.CallbackContainer.Callback;
Action<IComponentRegistry> updated = reg => if(predicate(reg)) { original(reg); };
rb.CallbackContainer.Callback = updated;
return rb; This would change the The upside is that it might allow for a better syntax. I'm not sure if it would open any additional doors for future enhancements or just be another property forever part of the API. Potential gotchaSince I haven't gotten terribly far with implementation, I don't know if it'll be a gotcha yet or not, but... Whenever you query an I'm not sure what might happen if you query the registry while you're still trying to register things, which is the case during callback execution in |
As part of my experimentation, I made some assumptions to answer the questions about the design. Perhaps changing some of the decisions would impact the design.
|
I just pushed something to a branch called // Provide a Predicate<IComponentRegistry>
builder
.RegisterType<Something>()
.OnlyIf(reg => { /* Do something with IComponentRegistry */ });
// or provide a service type
builder
.RegisterType<First>()
.As<IService>();
builder
.RegisterType<Second>()
.As<IService>()
.IfNotRegistered(typeof(IService)); The only interface broken is Interested in opinions/feedback. |
Version |
I published Autofac 4.4.0 to NuGet which includes the |
Just a note that it was a binary breaking change ( Quite easy to fix, but I thought I'd post it as it might be useful for someone else googling the error:
|
@ashmind Thanks for leaving the note for others to find. |
In fact, it is also very useful to detect directly from So I think such api is very useful:
|
Is there a way to register a specific Can the modules use |
Hmm, I came up with the following helper method. Maybe it helps somebody out there:
|
I think the missing features is "RegisterDefault" which means... at the point that the type is resolved. If there is not other implementation defined, then use this one. Great for implementing a NullObject pattern. |
From alex.meyergleaves on November 12, 2013 22:37:43
This was proposed by Jacek as shown in his clone. https://code.google.com/r/jszumigaj-autofac/ The idea is to prevent duplicate registration from being made, different to PreserveExistingDefaults which still adds the registration. e.g.
The changes look good but do break the existing API, and such I suggest we leave this for the 4.0 milestone. There is already work that needs to be done for PreserveExistingDefaults in regards to its behaviour in nested lifetime scopes: #272 Perhaps we should consider introducing a single Enum to describe the different override behaviours?
Original issue: http://code.google.com/p/autofac/issues/detail?id=469
The text was updated successfully, but these errors were encountered: