Resolving a collection of services from a service type - autofac

I have a rather complex bit of resolving going on in Autofac. Basically I want all the objects in the container which implement a specifically named method with a specific argument type. I have implemented some somewhat insane code to get it for me
var services = (from registrations in _componentContext.ComponentRegistry.Registrations
from service in registrations.Services
select service).Distinct();
foreach (var service in services.OfType<Autofac.Core.TypedService>())
{
foreach (var method in service.ServiceType.GetMethods().Where(m => m.Name == "Handle"
&& m.GetParameters().Where(p => p.ParameterType.IsAssignableFrom(implementedInterface)).Count() > 0))
{
var handler = _componentContext.Resolve(service.ServiceType);
method.Invoke(handler, new Object[] { convertedMessage });
}
}
My problem arises in that the handler returned the the resolution step is always the same handler and I cannot see a way to resolve a collection of the the registrations which are tied to the service as one might normally do with container.Resolve>().
I feel like I'm pushing pretty hard against what AutoFac was designed to do and might do better with a MEF based solution. Is there an easy AutoFac based solution to this issue or should I hop over to a more composition based approach?

G'day,
In MEF you could use 'Method Exports' for this (http://mef.codeplex.com/wikipage?title=Declaring%20Exports) but that might be a bit drastic. There are a couple of ways to achieve what you want in Autofac.
You can make the above code work by searching for registrations rather than services:
var implementorMethods = _componentContext.ComponentRegistry.Registrations
.Select(r => new {
Registration = r,
HandlerMethod = r.Services.OfType<TypedService>()
.SelectMany(ts => ts.ServiceType.GetMethods()
.Where(m => m.Name == "Handle" && ...))
.FirstOrDefault()
})
.Where(im => im.HandlerMethod != null);
foreach (var im in implementorMethods)
{
var handler = _componentContext.ResolveComponent(im.Registration, new List<Parameter>());
im.HandlerMethod.Invoke(handler, new object[] { convertedMessage });
}
I.e. implementorMethods is a list of the components implementing a handler method, along with the method itself. ResolveComponent() doesn't rely on a service to identify the implementation, so there's no problem with the service not uniquely identifying a particular implementor.
This technique in general will probably perform poorly (if perf is a concern here) but also as you suspect will work against the design goals of Autofac (and MEF,) eliminating some of the benefits.
Ideally you need to define a contract for handlers that will let you look up all handlers for a message type in a single operation.
The typical recipe looks like:
interface IHandler<TMessage>
{
void Handle(TMessage message);
}
Handlers then implement the appropriate interface:
class FooHandler : IHandler<Foo> { ... }
...and get registered at build-time like so:
var builder = new ContainerBuilder();
builder.RegisterAssemblyTypes(typeof(FooHandler).Assembly)
.AsClosedTypesOf(typeof(IHandler<>));
To invoke the handlers, define a message dispatcher contract:
interface IMessageDispatcher
{
void Dispatch(object message);
}
...and then its implementation:
class AutofacMessageDispatcher : IMessageDispatcher
{
static readonly MethodInfo GenericDispatchMethod =
typeof(AutofacMessageDispatcher).GetMethod(
"GenericDispatch", BindingFlags.NonPublic | BindingFlags.Instance);
IComponentContext _cc;
public AutofacMessageDispatcher(IComponentContext cc)
{
_cc = cc;
}
public void Dispatch(object message)
{
var dispatchMethod = GenericDispatchMethod
.MakeGenericMethod(message.GetType());
dispatchMethod.Invoke(this, new[] { message });
}
void GenericDispatch<TMessage>(TMessage message)
{
var handlers = _cc.Resolve<IEnumerable<IHandler<TMessage>>>();
foreach (var handler in handlers)
handler.Handle(message);
}
}
...which is registered like so:
builder.RegisterType<AutofacMessageDispatcher>()
.As<IMessageDispatcher>();
The component that feeds in the messages will then resolve/use IMessageDispatcher to get the messages to the handlers.
var dispatcher = _cc.Resolve<IMessageDispatcher>();
dispatcher.Dispatch(message);
There are still ways to do this without the interface, but all rely on creating some kind of contract that uniquely defines handlers for a particular message (e.g. a delegate.)
In the long run the generic handler pattern will be the easiest to maintain.
Hope this helps, Nick.

Related

Time-driven lifetime scope in singleton ASP.NET Web API controller

Consider the web controller that implements some API by wrapping downstream service that requires token to be called. The token has the expiration, so I'm after some kind of time-driven scope that re-acquires the token and re-creates client in case the token is expired:
MyController: Controller
{
IServiceAPI _downstreamServcie;
MyController (IServiceAPI downstreamService)
{
}
}
....
builder.Register(c => {
Token token = generateToken() ..
return new ServiceAPIClient(token) ;
})
.As<IServiceAPI>()
I don't want to register MyController with per-request-scope because of performance issues.
Having spring background, such kind of captive dependency is resolved in spring by injecting singleton dynamic proxy that forwards the call to the right scoped-object (request/session/custom).
What would be the right way to implement the same with Autofac?
Thanks
[UPDATE]
Digging into Autofac documentation, I've found IResolveMiddleware interface that can be used to dynamically create/change scope :
class TokenScopeResolverMiddleware : IResolveMiddleware {
private ISharingLifetimeScope _currentTokenScope;
private ISharingLifetimeScope _prevTokenScope;
public void Execute(ResolveRequestContext context, Action<ResolveRequestContext> next) {
if (null == _currentTokenScope) {
lock (this) {
if (null == _currentTokenScope) {
RolloverScope(context);
}
}
}
if (!CanUseCurrentToken()) {
lock (this) {
if (!CanUseCurrentToken()) {
RolloverScope(context);
}
}
}
context.ChangeScope(_currentTokenScope);
next(context);
}
private bool CanUseCurrentToken() {
AuthenticationResult authResult = _currentTokenScope.Resolve<AuthenticationResult>();
TimeSpan expiresIn = authResult.ExpiresOn - DateTime.Now;
return expiresIn > TimeSpan.FromSeconds(20);
}
private void RolloverScope(ResolveRequestContext context) {
if (null != _prevTokenScope) {
_prevTokenScope.Dispose();
}
_prevTokenScope = _currentTokenScope; // give another `expiration time` grace period before disposing token scope
_currentTokenScope =
context.ActivationScope.RootLifetimeScope.BeginLifetimeScope("token") as ISharingLifetimeScope;
}
public PipelinePhase Phase { get; } = PipelinePhase.ScopeSelection;
}
Usage :
builder.Register(c => {
AuthenticationResult result = // acquire token
return result;
})
.InstancePerMatchingLifetimeScope("token");
builder.Register(c => {
return new Client(c.Resolve<AuthenticationResult>().Token)
})
.InstancePerMatchingLifetimeScope("token");
builder.RegisterServiceMiddleware<Client>(new TokenScopeResolverMiddleware());
Any better suggestions ?
I think you're likely looking for the Func<T> relationship, or something like it, where you inject a factory that dynamically resolves the client as you need it.
public class MyController
{
private readonly Func<IClient> _clientFactory;
public MyController(Func<IClient> clientFactory)
{
this._clientFactory = clientFactory;
}
public void DoWork()
{
var client = this._clientFactory();
client.CallApi();
}
}
Your lambda could be just about anything as long as it runs synchronously. Don't forget DI is more about injecting dependencies (object construction) than it is about managing your application's state, orchestrating logic, or executing factories on your behalf, though admittedly it's pretty convenient to try to multipurpose it in those ways.
var builder = new ContainerBuilder();
builder.Register(ctx =>
{
var token = GetOrRefreshToken();
return new Client(token);
}).As<IClient>();
A word of warning - you may run into memory leak trouble.
If the IClient implementation is also IDisposable, Autofac is going to hold onto every IClient created until the lifetime scope is disposed because the container is responsible for creating objects... and disposing them. If your controller is a singleton, that means the Func<IClient> will be resolving from the root lifetime scope (the container itself), which further means you can't dispose the captured IClient instances without disposing the whole application container.
You can disable that with ExternallyOwned but then you also will have to dispose things yourself.
It may be better to unwind things just a little and try to do less in DI, more with your own code. For example, actually create your own client factory that knows when to refresh the token, how to construct and dispose of clients, etc. You may even want to look at stuff like IHttpClientFactory which is specifically meant for stuff like this. Then instead of injecting the client, inject the factory and use the factory to get a client instance as you need it. That is, instead of injecting Func<IClient>, inject IHttpClientFactory or something similar, thus reducing the need to try to force the captive dependency to behave and instead addressing the challenge with a solution possibly more appropriate.

How to resolve generic type at runtime

I'm trying to build a command processor that can take any command that implements a marker interface (or maybe descends from a base class). The processor will handle the command that it is asked to process. However I'm struggling with resolving the true generic type as Resolve(Type) returns an object.
I'm not sure is how to cast this if at all possible?
public void Process(ICommand command)
{
var c = command.GetType();
var t = typeof(ICommandHandler<>).MakeGenericType(new[] { c });
var o = container.Resolve(t);
//((ICommandHandler)o).Handle(command); *** This doesn't work
}
The calling code would be something like this -
Dispatcher.Process(new SomeCommand(Guid.NewGuid(),"Param1",12345));
If you absolutely have to call the ICommandHandler<T>.Handle method and you have no other control over the design of the system, then reflection may be your only choice. There's no great way to deal with the switch from generic to non-generic.
Otherwise, you may have a couple of options.
First, if your Dispatcher.Process can be made generic, you can save all the casting.
public static class Dispatcher
{
public static void Process<T>(T command) where T : ICommand
{
var handler = container.Resolve<ICommandHandler<T>>();
handler.Handle(command);
}
}
This is a pretty common solution to a problem like this that I've seen out in the wild.
If you can't do that, then you may be able to make your ICommandHandler<T> interface implement a non-generic ICommandHandler base interface.
public interface ICommandHandler
{
void Handle(ICommand command);
}
public interface ICommandHandler<T> : ICommandHandler
{
void Handle(T command);
}
In this latter case you'd have to switch your strongly-typed command handler implementations to call the same internal logic for generic or basic handling or you'll get different handling based on the call, which would be bad:
public class SomeCommandHandler : ICommandHandler<SomeCommand>
{
public void Handle(ICommand command)
{
var castCommand = command as SomeCommand;
if(castCommand == null)
{
throw new NotSupportedException("Wrong command type.");
}
// Hand off to the strongly-typed version.
this.Handle(castCommand);
}
public void Handle(SomeCommand command)
{
// Here's the actual handling logic.
}
}
Then when you resolve the strongly-typed ICommandHandler<T> your cast down to ICommandHandler (as shown in your question's sample code) will work.
This is also a pretty common solution, but I've seen it more in systems that existed before generics were available where an updated API was being added.
However, in all cases here, the problem really isn't that Autofac is returning an object; it's a class/type design problem that affects any generic-to-non-generic conversion scenario.
Using Reflection - but is this the best way to approach this?
public void Process(Command command)
{
var c = command.GetType();
var ot = typeof(ICommandHandler<>);
var type = ot.MakeGenericType(new[] { c });
var mi = type.GetMethod("Handle");
var o = container.Resolve(type);
mi.Invoke(o, new object[] { command });
}

MEF and IObservables

I have a singleton IObservable that returns the results of a Linq query. I have another class that listens to the IObservable to structure a message. That class is Exported through MEF, and I can import it and get asynchronous results from the Linq query.
My problem is that after initial composition takes place, I don't get any renotification on changes when the data supplied to the Linq query changes. I implemented INotifyPropertyChanged on the singleton, thinking it word make the exported class requery for a new IObservable, but this doesn't happen.
Maybe I'm not understanding something about the lifetime of MEF containers, or about property notification. I'd appreciate any help.
Below are the singleton and the exported class. I've left out some pieces of code that can be inferred, like the PropertyChanged event handlers and such. Suffice to say, that does work when the underlying Session data changes. The singleton raises a change event for UsersInCurrentSystem, but there is never any request for a new IObservable from the UsersInCurrentSystem property.
public class SingletonObserver: INotifyPropertyChanged
{
private static readonly SingletonObserver _instance = new SingletonObserver();
static SingletonObserver() { }
private SingletonObserver()
{
Session.ObserveProperty(xx => xx.CurrentSystem, true)
.Subscribe(x =>
{
this.RaisePropertyChanged(() => this.UsersInCurrentSystem);
});
}
public static SingletonObserverInstance { get { return _instance; } }
public IObservable<User> UsersInCurrentSystem
{
get
{
var x = from user in Session.CurrentSystem.Users
select user;
return x.ToObservable();
}
}
}
[Export]
public class UserStatus : INotifyPropertyChanged
{
private string _data = string.Empty;
public UserStatus
{
SingletonObserver.Instance.UsersInCurrentSystem.Subscribe(sender =>
{
//set _data according to information in sender
//raise PropertyChanged for Data
}
}
public string Data
{
get { return _data; } }
}
}
My problem is that after initial composition takes place, I don't get any renotification on changes when the data supplied to the Linq query changes.
By default MEF will only compose parts once. When a part has been composed, the same instance will be supplied to all imports. The part will not be recreated unless you explicitly do so.
In your case, if the data of a part change, even if it implements INotifyPropertyChanged, MEF will not create a new one, and you don't need to anyway.
I implemented INotifyPropertyChanged on the singleton, thinking it word make the exported class requery for a new IObservable
No.
Maybe I'm not understanding something about the lifetime of MEF containers, or about property notification.
Property notification allows you to react to a change in the property and has no direct effect on MEF. As for the container's lifetime, it will remain active until it is disposed. While it is still active, the container will keep references to it's compose parts. It's actually a little more complex than that, as parts can have different CreationPolicy that affects how MEF holds the part, I refer you to the following page: Parts Lifetime for more information.
MEF does allow for something called Recomposition. You can set it likewise:
[Import(AllowRecomposition=true)]
What this does tough is allow MEF to recompose parts when new parts are available or existing parts aren't available anymore. From what I understand it isn't what you are referring to in your question.

Replace registration in Autofac

I have an application which does data processing. There is
class Pipeline {
IEnumerable<IFilter> Filters {get; set;}
I register filters implementations as
builder.RegisterType<DiversityFilter>().As<IFilter>();
builder.RegisterType<OverflowFilter>().As<IFilter>();
...
So far so good. Now, for experimentation and fine-tuning I want to be able to override any filter implementation in config file with a program(script) which would read data from stdin, process it and send data to stdout. I've implemented a module with "fileName", "args" and "insteadOf" custom properties, described module in xml and got it called.
In the module I register my "ExecutableFilter" but how do I make it run "instead of" desired service? If I try do it like this:
builder.RegisterType<ExecutableFilter>().As<DiversityFilter>()
then I get an exception " The type 'ExecutableFilter' is not assignable to service 'DiversityFilter'.". Ok, this is logical. But what are my options then?
Once you've overridden the registration for IFilter "After" with your wire-tap, you won't be able to resolve it from the container, as the new registration will be activated instead, hence the circular lookup.
Instead, create and register a module that hooks into the filter's creation, and replaces the instance with the 'wire tapped' one:
class WiretapModule : Module
{
override void AttachToComponentRegistration(
IComponentRegistration registration,
IComponentRegistry registry)
{
if (registration.Services.OfType<KeyedService>().Any(
s => s.ServiceKey == After && s.ServiceType == typeof(IFilter)))
{
registration.Activating += (s, e) => {
e.Instance = new WireTap((IFilter)e.Instance, new ExecuteProvider(fileName, args))
};
}
}
}
(Cross-posted to the Autofac group: https://groups.google.com/forum/#!topic/autofac/yLbTeuCObrU)
What you describe is part container work, part business logic. The challenge is to keep separation of concerns here. IMO, the container should do what it is supposed to do, that is building and serving up instances or collections thereof. It should not do the "instead of" in this case. I would rather "enrich" the services with enough information so that the pipeline make the decision.
The "enrichment" can be accomplished by making the ExecutableFilter implement a more distinct interface.
interface IInsteadOfFilter : IFilter { }
...
builder.RegisterType<ExecutableFilter>().As<IFilter>();
...
class Pipeline
{
IEnumerable<IFilter> Filters {get;set;}
public void DoTheFiltering()
{
var filters = Filters.OfType<IInsteadOfFilter>();
if (!insteadof.Any())
filters = Filters;
foreach(var filter in filters)
{
...
}
}
You could also solve this using the metadata infrastructure, which gives us an even more expressive way of differentiating services.

Entity Framework and Entity Tracker Problems

If I run the following code it throws the following error:
An entity object cannot be referenced by multiple instances of IEntityChangeTracker
public void Save(Category category)
{
using(var db = new NorthwindContext())
{
if(category.CategoryID == 0)
{
db.AddToCategorySet(category);
}
else
{
//category.RemoveTracker();
db.Attach(category);
}
db.SaveChanges();
}
}
The reason is of course that the category is sent from interface which we got from GetById method which already attached the EntityChangeTracker to the category object. I also tried to set the entity tracker to null but it did not update the category object.
protected void Btn_Update_Category_Click(object sender, EventArgs e)
{
_categoryRepository = new CategoryRepository();
int categoryId = Int32.Parse(txtCategoryId.Text);
var category = _categoryRepository.GetById(categoryId);
category.CategoryName = txtUpdateCategoryName.Text;
_categoryRepository.Save(category);
}
I'm still learning Entity Framework myself, but maybe I can help a little. When working with the Entity Framework, you need to be aware of how you're handling different contexts. It looks like you're trying to localize your context as much as possible by saying:
public void Save(Category category)
{
using (var db = new NorthwindContext())
{
...
}
}
... within your data access method. Did you do the same thing in your GetById method? If so, did you remember to detach the object you got back so that it could be attached later in a different context?
public Category GetById(int categoryId)
{
using (var db = new NorthwindContext())
{
Category category = (from c in db.Category where Category.ID == categoryId select c).First();
db.Detach(category);
}
}
That way when you call Attach it isn't trying to step on an already-attached context. Does that help?
As you pointed out in your comment, this poses a problem when you're trying to modify an item and then tell your database layer to save it, because once an item is detached from its context, it no longer keeps track of the changes that were made to it. There are a few ways I can think of to get around this problem, none of them perfect.
If your architecture supports it, you could expand the scope of your context enough that your Save method could use the same context that your GetById method uses. This helps to avoid the whole attach/detach problem entirely, but it might push your data layer a little closer to your business logic than you would like.
You can load a new instance of the item out of the new context based on its ID, set all of its properties based on the category that is passed in, and then save it. This costs two database round-trips for what should really only need one, and it isn't very maintainable.
You can dig into the context itself to mark the Category's properties as changed.
For example:
public void Save(Category category)
{
using (var db = new NorthwindContext())
{
db.Attach(category);
var stateEntry = db.ObjectStateManager.GetObjectStateEntry(category);
foreach (var propertyName in stateEntry.CurrentValues.DataRecordInfo.FieldMetadata.Select(fm => fm.FieldType.Name)) {
stateEntry.SetModifiedProperty(propertyName);
}
db.SaveChanges();
}
}
This looks a little uglier, but should be more performant and maintainable overall. Plus, if you want, you could make it generic enough to throw into an extension method somewhere so you don't have to see or repeat the ugly code, but you still get the functionality out of it.