In the past I've built a MessageDispatcher component that scans an assembly for types decorated with certain attributes and initializes an instance of each. Then, when any object is fed to the MessageDispatcher instance, every previously initialized instance which contains a method which signature contains the type of the passed object has said method triggered with the specified parameter. For example, in a scenario like:
[Listener]
public class MyListener
{
MessageDispatcher _dispatcher; //Assigned elsewhere
[MessageListener]
public async Task DoSomething(int value)
{
var otherValue = await _dispatcher.Next<string>();
Console.WriteLine($"{value} is {otherValue}.");
}
}
The following code initializes an instance of the MyListener class, calls DoSomething and prints "7 is okay.":
var listener = new MessageDispatcher(typeof (ListenerAttribute));
listener.Dispatch(7);
listener.Dispatch("okay");
I would like to know if there are any libraries out there that are dedicated to or include a service like such. It has to be able to:
Scan assemblies and initialize types based on an attribute.
Dynamically "subscribe" to certain types
"Wait" on a value to be pumped from the dispatcher (like with the Next method in my example).
(as library recommendations is not allowed per the SO rules, here is an attempt to instead answer with an implementation)
You can get that with virtually any IoC. All they need is to be able to register services using an attribute or some other conventional way.
As for the message dispatching. Just create an interface like IMessageHandler<TMessage>. Implement it on all classes that should handle messages.
Example:
public interface IMessageHandler<TMessage>
{
void Handle(TMessage msg);
}
public class SomeService : IMessageHandler<UserCreated>
{
//[.. all other methods ..]
public void Handle(UserCreated msg)
{
// ...
}
}
To publish messages you create a dispatcher. Since you use a container you do not have to make it static. Use your container inside it (service location) to dispatch the messages. Now some peeps might say oohh no, service location is anti-pattern, buhuhuhu. Well no. Not in all cases. In this case it's an implementation details in a class with the specific purpose to identify and invoke other classes.
public interface IMessageDispatcher
{
void Dispatch<TMessage>(TMessage msg);
}
// The actual implementation differs
// depending on your choice of container.
public class ContainerBasedMessageDispatcher : IMessageDispatcher
{
Container _container;
public ContainerBasedMessageDispatcher(Container container)
{
_container = container;
}
public void Dispatch<TMessage>(TMessage message)
{
using (var scope = container.BeginLifetimeScope())
{
var handlers = scope.Resolve<IEnumerable<IMessageHandler<TMessage>>();
foreach (var handler in handlers)
{
handler.Handle(message);
}
}
}
}
The code is written directly in SO. So it might not work as-is. But hopefully it's given you an idea how to achieve what you want.
Usage:
public class UserService
{
IMessageDispatcher _dispatcher;
public UserService(IMessageDispatcher dispatcher)
{
_dispatcher = dispatcher;
}
public void Create(User user)
{
//[...]
_dispatcher.Dispatch(new UserCreated(user.Id));
}
}
this do however not dynamically allow you to subscribe on what you want. If just ignoring unwanted messages is not feasible. Then this answer is not for you.
Related
I have a class that works with a network via multiple resources. Its constructor receives arguments that are resolved at runtime by IoC container (StructureMap):
public NetworkWorker(IRetryService retryService, ILog log)
{ ... }
What I need is to control the number of resources this class uses on a use-case level - for example, client A need NetworkWorker instance that allows only one operation at a time, while client B need 10 ops at a time.
Currently this number is hardcoded in the constructor. The only way I see is to add a method void Configure(int resourceCount) that each client of NetworkWorker would call with a different value. Or may be there's a better way I don't see?
This class can do different things, but number of resources is required for every method call (Get/Send/etc methods).
P.S. is this a known technique (with a Configure method)? If it is, what's the name for it? smth like 'two-step initialization'?
I'll presume this NetworkWorker has multiple methods (otherwise you could just add a parameter to that single method).
You could use a factory pattern:
public interface INetworkWorkerFactory
{
NetworkWorker Create(int numberOfResources);
}
public class NetworkWorkerFactory : INetworkWorkerFactory
{
private readonly IContainer _container;
public NetworkWorkerFactory(IContainer container)
{
_container = container;
}
public NewtorkWorker Create(int numberOfResources)
{
var retryService = _container.GetInstance<IRetryService>();
var log = _container.GetInstance<ILog>();
return new NewtorkWorker(retryService, log, numberOfResources);
}
}
(or simply inject the required dependencies instead of the container)
and then simply
private readonly INetworkWorkerFactory _networkWorkerFactory;
public C(INetworkWorkerFactory networkWorkerFactory)
{
_networkWorkerFactory = networkWorkerFactory;
}
public void M()
{
var networkWorker = _networkWorkerFactory.Create(10);
}
Autofac uses delegate factories for this.
Other containers have equivalent mechanisms of providing auto-generated Abstract Factories - #ploeh has an awesome SO post aggregating examples.
The code in your question would look like so:
public delegate NetworkWorker Factory(IRetryService retryService);
public NetworkWorker(IRetryService retryService, ILog log)
{ ... }
A consumer would look like so (stolen from Alex's answer)
readonly NetworkWorker.Factory _networkWorkerFactory;
public C(NetworkWorker.Factory networkWorkerFactory)
{
_networkWorkerFactory = networkWorkerFactory;
}
public void M()
{
var networkWorker = _networkWorkerFactory(10);
...
}
The key difference is that you do not declare either an interface or an impl for the Abstract Factory - the delegate is the interface and Autofac 'just knows' to make the rest happen.
Another benefit of this approach (other than the code reduction) is that there's a natural path to transitioning the code to Pure DI)
I'm taking a stab at properly implementing DI in my Xamarin Android application using Autofac but I'm having issues understanding how I should handle instantiating objects that require data passed into their constructor. For example one of our viewmodels needs a string and a guid passed in to its constructor. Something that looks promising is Delegate Functions offered by Autofac. This is where the line between Service Locator and DI appears to blur, at least in my mind. In order to use the Delegate Functions you must call container.Resolve, or rather it's recommended to use the IComponentContext.Resolve. Many blogs recommend not using Resolve outside of the bootstapper/main entry point. Is there something I am missing here? Is there a better way to create objects using DI? I am familiar with the Factory pattern to create objects but I feel that I'm losing the benefits of DI going that route since I am back to manually passing in services/objects to the newly created object. Thanks for any feedback!
It is not recommended to call container.Resolve() to use a delegate factory. The correct way is shown on the delegate factories page that you already linked to:
public class Portfolio
{
Shareholding.Factory ShareholdingFactory { get; set; }
IList<Shareholding> _holdings = new List<Shareholding>();
public Portfolio(Shareholding.Factory shareholdingFactory)
{
ShareholdingFactory = shareholdingFactory;
}
public void Add(string symbol, uint holding)
{
_holdings.Add(ShareholdingFactory(symbol, holding));
}
}
When the docs show an explicit call to container.Resolve() you should realize that they are not showing best practice, they are simply proving that it can be resolved without coding up a whole new class (like Portfolio) to consume it.
In order to use the Delegate Functions you must call container.Resolve
No, at least not in this case.
Assuming you have registered Shareholding. Now you can ask a dependency on Func<Shareholding>, ie. something hat returns a Shareholding when you call it.
But as the Shareholding constructor has two parameters, it cannot be resolved without supplying those parameters. Just add them to the declaration like this: Func<string, uint, Shareholding>. Now you can resolve the dependency when you supply those parameters.
Here is a better example.
I recently (yesterday) faced the same problem I wound up using the ServiceClient object you see in the code below. This object addresses your question about using the container outside of the bootstrapper. I have read arguments that say not to pass the container around and I think they are mostly valid. In my case however the ServiceClient class represents a single point of entry into my service layer so I thought it was appropriate to pass the container.
The way I use this at the moment is to pass an instance of ServiceClient into my BaseController:
// In Global.asax.cs
builder.RegisterControllers(typeof(MvcApplication).Assembly);
builder.RegisterType<ServiceClient>().As<IServiceClient>();
BaseController:
public abstract class BaseController<T> : Controller where T :class
{
public IServiceClient ServiceClient { get; set; }
public BaseController(IServiceClient serviceClient)
{
ServiceClient = serviceClient;
}
}
In my controller I can resolve, instantiate, and call a service that uses unmanaged resources with just one line like this:
myViewModel = await ServiceClient.OfType<ICustomerService>().TryAsync(x => x.GetCustomerByID(id));
ServiceClient:
public class ServiceClient : IServiceClient
{
private IComponentContext _container;
public ServiceClient(IComponentContext container)
{
_container = container;
}
public ServiceCallWrapper<T> OfType<T>() where T : class, IDisposable
{
return new ServiceCallWrapper<T>(_container);
}
}
public class ServiceCallWrapper<T> : IServiceCallWrapper<T> where T : class, IDisposable
{
private IComponentContext _container;
internal ServiceCallWrapper(IComponentContext container)
{
_container = container;
}
public void Try(Action<T> method)
{
// consider try/catch/log/throw here
using (T client = _container.Resolve<T>())
{
method(client);
}
}
public TResult Try<TResult>(Func<T, TResult> method)
{
using (T client = _container.Resolve<T>())
{
return method(client);
}
}
public async Task TryAsync(Func<T, Task> method)
{
using (T client = _container.Resolve<T>())
{
await method(client);
}
}
public async Task<TResult> TryAsync<TResult>(Func<T, Task<TResult>> method)
{
using (T client = _container.Resolve<T>())
{
return await method(client);
}
}
}
Follow up to an older question here. Say I have a registration like the following:
container.Register(typeof(IHandleCommand<>), _handlerAssemblies, Lifestyle.Transient);
container.RegisterDecorator(typeof(IHandleCommand<>),
typeof(MetricsCommandHandlerWrapper<>), Lifestyle.Singleton);
Where the MetricsCommandHandlerWrapper is defined like so:
public class MetricsCommandHandlerWrapper<T> : IHandleCommand<T> where T: ICommand
{
private readonly ICollectMetrics _metrics;
private readonly Func<IHandleCommand<T>> _handlerFactory;
public MetricsCommandHandlerWrapper(ICollectMetrics metrics,
Func<IHandleCommand<T>> handlerFactory)
{
_metrics = metrics;
_handlerFactory = handlerFactory;
}
public async Task HandleAsync(T command)
{
// code to record metrics around command handling which eventually invokes
await _handlerFactory().HandleAsync(command).ConfigureAwait(false);
}
}
How can I write a unit test that asserts the actual decoratee handlers are registered with Transient lifestyle?
I have tried composing the root and inspecting the registration for a closed IHandleCommand<FakeCommand> type, which reveals an ImplementationType of MetricsCommandHandlerWrapper<FakeCommand> as expected. Invoking GetRelationships() on that registration reveals its 2 dependencies, ICollectMetrics and the one I am interested in, the Func<IHandleCommand<FakeCommand>> factory delegate, which is registered as a Singleton. However invoking .Dependency.GetInstance() on that factory delegate throws an exception that the instance producer returned null.
Is there any way to assert that the inner decoratee is registered as Transient, and if so, how?
The use of the Func<T> delays the building of the object graph, and from perspective of the diagnostic system, the graphs stops at that point. So, it's not possible to do this analysis.
Instead of completely relying on Simple Injector's internals however, you can also choose to make some minor changing in your application to allow testing decorators.
What you can do is implement an IDecorator abstraction on your decorators:
public interface IDecorator {
object Decoratee { get; }
}
Now each decorator can implement this interface. For the MetricsCommandHandlerWrapper<T>, it might look as follows:
public class MetricsCommandHandlerWrapper<T> : IHandleCommand<T>, IDecorator where T: ICommand
{
private readonly ICollectMetrics _metrics;
private readonly Func<IHandleCommand<T>> _handlerFactory;
public MetricsCommandHandlerWrapper(ICollectMetrics metrics,
Func<IHandleCommand<T>> handlerFactory) {
_metrics = metrics;
_handlerFactory = handlerFactory;
}
public object Decoratee { get { return _handlerFactory(); }
public async Task HandleAsync(T command) { ... }
}
On top of the IDecorator interface, you can define a simple extension method:
public static IEnumerable<Type> GetDecoratorChain(this IDecorator decorator) {
while (decorator != null) {
yield return decorator.GetType();
decorator = decorator.Decoratee as IDecorator;
}
}
Inside your unit test you can now resolve a handler and ask for the list of applied decorators. Using this list you can verify whether decorators are applied in the correct order.
I have an abstract base class which contains several methods, of which one I need to intercept at all times. The base class can be inherited by user defined classes and registered with the container on application startup. In the event user hasn't registered one, the container installer will register one itself.
Here's the problem - the user should not have to worry about adding the interceptor. Container should add it on its own, regardless of who and where registered the component.
This is what I'm doing now:
if(!container.Kernel.HasComponent(typeof(MyBaseComponent)))
container.Register(Component.For<MyComponent>()
.Interceptors(InterceptorReference
.ForType<MyComponentMethodInterceptor>())
.SelectedWith(new MyComponentMethodSelector()).AtIndex(1));
MyComponentMethodSelector is a simple IInterceptorSelector which checks whether the methodname equals the one I need to intercept (in which case a MyComponentMethodInterceptor gets added to it).
As you can see it will check whether the component is already registered first.
The question is - do I have a way of adding an interceptor if it IS already registered? The most obvious choice that comes to mind is using an IContributeComponentModelConstruction, however at that point I will run into not being able to select the method which the interceptor gets added to. Or is there?
EDIT:
I should have been a little more specific. I need to add an interceptor for a specific method only. Hence why I'm using a MyComponentMethodSelector. I am aware of IContributeComponentModel, and I started out with that until I realised there was no way for me to add a method selector.
You can easily add configuration to a component with a ComponentModel construction contributor that is called at the construction of the component model for your service by implementing IContributeComponentModelConstruction.
Let's say you want to add an interceptor to any implementation of IEventuallyRegistered, and if the user didn't register a custom component you want to use DefaultRegistration:
public interface IEventuallyRegistered { void test(); }
public class DefaultRegistration : IEventuallyRegistered { public void test() { } }
public class EventuallyRegisteredInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation) { invocation.Proceed(); }
}
internal class Program
{
private static void Main(string[] args)
{
var container = new Castle.Windsor.WindsorContainer();
container.Register(Component.For<EventuallyRegisteredInterceptor>());
container.Register(Component.For<IEventuallyRegistered>().ImplementedBy<DefaultRegistration>());
// I'm not doing the optional registration, I just want to
// demonstrate upgrading a additional configuration
var t = container.Resolve<IEventuallyRegistered>();
t.test();
}
}
Implementing the IContributeComponentModelConstruction interface lets you change the configuration of the component model when it is created:
public class RequireInterception : IContributeComponentModelConstruction
{
public void ProcessModel(IKernel kernel, ComponentModel model)
{
if (model.Services.Contains(typeof(IEventuallyRegistered)))
{
model.Interceptors.Add(new InterceptorReference(typeof(EventuallyRegisteredInterceptor)));
}
}
}
Then add the component to the container before registering your component:
container.Kernel.ComponentModelBuilder.AddContributor(new RequireInterception());
container.Register(Component.For<IEventuallyRegistered>().ImplementedBy<DefaultRegistration>());
Even though it is possible to do it through the ComponentRegistered event of the kernel with a facility, this is not recommended; since it was included in the original answer I'm including it but I'm pushing it down. You would start by creating a facility
public class InterceptionFacility : AbstractFacility
{
protected override void Init()
{
Kernel.ComponentRegistered += new Castle.MicroKernel.ComponentDataDelegate(Kernel_ComponentRegistration);
}
void Kernel_ComponentRegistration(string key, Castle.MicroKernel.IHandler handler)
{
if (typeof(IEventuallyRegistered).IsAssignableFrom(handler.ComponentModel.Implementation))
{
handler.ComponentModel.Interceptors.Add(new InterceptorReference(typeof(EventuallyRegisteredInterceptor)));
}
}
}
Then add the facility to the container before the registration of your component, or your facility will miss the event when registering your component:
container.AddFacility<InterceptionFacility>();
container.Register(Component.For<IEventuallyRegistered>().ImplementedBy<DefaultRegistration>());
EDIT: I've cleaned this question up significantly after solving my problem, including changing the title.
I have a MessageChannel interface which defines (unsurprisingly) a channel that my classes can use to push messages to the end user.
Normally this MessageChannel is a Singleton and is bound to a ViewModel that implements the MessageChannel interface. Essentially, there is a single location at the top of my application where messages to the user will be shown. So far its worked pretty well.
This MessageChannel is used in a lot of places, one of which is in some operation classes that I have setup.
I now have a need for a LOCAL MessageChannel, such messages being posted in some reduced scope get posted to that local MessageChannel and not the global one.
What this means is that I need to be able to create instances of a ViewModel (through a Factory), such that that particular instance has its own MessageChannel instance AND that MessageChannel instance is shared for all dependencies injected into that ViewModel (and their dependencies and so on).
Some classes to illustrate. I have simplified things somewhat, my messages are more than just strings:
using Ninject;
using Ninject.Extensions.Factory;
public interface MessageChannel
{
void PostMessage(string message);
}
public class MessageChannelViewModel : MessageChannel
{
public string Message { get; set; }
public void PostMessage(string message)
{
Message = message;
}
}
public interface Operation
{
void Do();
}
public interface OperationFactory
{
Operation Create();
}
public class DefaultOperation : Operation
{
public DefaultOperation(MessageChannel userMessages)
{
_UserMessages = userMessages;
}
private readonly MessageChannel _UserMessages;
public void Do()
{
// Do something.
_UserMessages.PostMessage("Success!");
}
}
public interface IsolatedViewModel
{
MessageChannelViewModel LocalMessages { get; }
}
public interface IsolatedViewModelFactory
{
IsolatedViewModel Create();
}
public class DefaultIsolatedViewModel : IsolatedViewModel
{
public IsolatedViewModel(MessageChannelViewModel localMessages, OperationFactory opFactory)
{
_OpFactory = opFactory;
LocalMessages = localMessages;
}
private readonly OperationFactory _OpFactory;
public MessageChannelViewModel LocalMessages { get; private set; }
}
public class Module : NinjectModule
{
public override void Load()
{
Bind<MessageChannel, MessageChannelViewModel>().To<MessageChannelViewModel>().InSingletonScope();
Bind<Operation>().To<DefaultOperation>();
Bind<OperationFactory>().ToFactory();
Bind<IsolatedViewModel>().To<DefaultIsolatedViewModel>();
Bind<IsolatedViewModelFactory>().ToFactory();
// Something to make it so the IsolatedViewModel DOESNT get the Singleton
// instance of the MessageChannelViewModel, and instead gets once of its own
// AND so the Operations created by the OperationFactory injected into the
// IsolatedViewModel get the SAME MessageChannel, so messages being posted
// from any place in the IsolatedViewModel's dependencies are shown only\
// locally.
}
}
I tried the NamedScope extension but I couldn't get it do what I wanted it to do.
I think you can try to use The Ninject Context Preservation Extension which adds support for recording (and making available to Contextual Binding rules) the context pertaining to factories that call the Kernel to Resolve Requests.
This enables you to add contextual conditions to your Bindings.
I ended up using a combination of Ninject.Extensions.ContextPreservation and Ninject.Extensions.NamedScope to accomplish what I wanted.
The completed example module looks like this:
public class Module : NinjectModule
{
public override void Load()
{
Bind<MessageChannel, MessageChannelViewModel>().To<MessageChannelViewModel>().InSingletonScope();
Bind<Operation>().To<DefaultOperation>();
Bind<OperationFactory>().ToFactory();
var uniqueName = "UNIQUE";
Bind<IsolatedViewModel>()
.To<DefaultIsolatedViewModel>()
.Named(uniqueName)
.DefinesNamedScope(uniqueName);
Bind<MessageChannel, MessageChannelViewModel>().To<MessageChannelViewModel>()
.WhenAnyAncestorNamed(uniqueName)
.InNamedScope(uniqueName);
Bind<IsolatedViewModelFactory>().ToFactory();
}
}
Theres two parts to it.
You need the ContextPreservation extension to choose the correct binding based on the context available at the time that you resolve the object instance. In this case I used a name as context, meaning that my special MessageChannel binding will be used when resolving the MessageChannel dependency for any dependencies required under the IsolatedViewModel.
I needed the NamedScope extension to ensure that only 1 instance of the MessageChannel was created under each IsolatedViewModel instance (i.e. the instance was shared for that IsolatedViewModel and all its dependencies).
Some other things to be aware of:
If you are using any ToMethod bindings and you use the Kernel inside the method, you'll need to make sure you use a ContextPreservingGet or you'll lose your context and the correct binding wont be selected.
You'll have to look very closely at your bindings and double check any Singleton bindings because if any of the dependencies of your isolated class are bound in Singleton scope, and they have dependencies on the MessageChannel (for example) its not going to work like you want it to. I had to remove a couple of Singleton scoped bindings as a result of this (for the better probably).