Is there any way to inject dependencies in to the Azure Service Fabric Actor's constructor?
Updated
Its all on github and myget now: https://github.com/s-innovations/S-Innovations.ServiceFabric.Unity
and integrates with aspnet core dependency injection without to much hassle, check the examples of the readme.md
I am a long time user of Unity and decided to make the core extension methods needed to have a nice dependency injection experience when working with actors.
My program.cs now looks like this:
internal static class Program
{
/// <summary>
/// This is the entry point of the service host process.
/// </summary>
private static void Main()
{
try
{
using (var container = new UnityContainer())
{
container.RegisterType<IMessageProcessorClientFactory, DummyFactory>(new HierarchicalLifetimeManager());
container.RegisterType<IMessageClusterConfigurationStore, test>(new HierarchicalLifetimeManager());
container.WithFabricContainer();
container.WithActor<MessageClusterActor>();
container.WithActor<QueueListenerActor>();
container.WithStatelessFactory<ManagementApiServiceFactory>("ManagementApiServiceType");
container.WithActor<VmssManagerActor>();
ServiceFabricEventSource.Current.ServiceTypeRegistered(Process.GetCurrentProcess().Id, typeof(ManagementApiService).Name);
Thread.Sleep(Timeout.Infinite); // Prevents this host process from terminating to keep the service host process running.
}
}
catch (Exception e)
{
ServiceFabricEventSource.Current.ActorHostInitializationFailed(e.ToString());
throw;
}
}
}
where I in actors and services can just put in my dependencies in the constructors.
public class VmssManagerActor : StatefulActor<VmssManagerActor.ActorState>, IVmssManagerActor, IRemindable
{
public const string CheckProvision = "CheckProvision";
/// <summary>
/// Cluster Configuration Store
/// </summary>
protected IMessageClusterConfigurationStore ClusterConfigStore { get; private set; }
public VmssManagerActor(IMessageClusterConfigurationStore clusterProvider)
{
ClusterConfigStore = clusterProvider;
}
If you feel this is useful and would like me to put it into a nuget package, upvote this answer.
One note about the implementation, each actor will get its own scope. This means that all dependencies registered with 'HierarchicalLifetimeManager' that implements IDisposable will automaticly get disposed in the actor OnDeactivationAsync. This was done by dynamicly proxying the actor class with a dynamic type that intercepts the call to OnDeactivationAsync. For this to work the Actor must be public defined.
IActorDeactivationInterception.cs
namespace SInnovations.Azure.ServiceFabric.Unity.Abstraction
{
/// <summary>
/// The <see cref="IActorDeactivationInterception"/> interface for defining an OnDeactivateInterception
/// </summary>
public interface IActorDeactivationInterception
{
void Intercept();
}
}
ActorProxyTypeFactory.cs
namespace SInnovations.Azure.ServiceFabric.Unity.Actors
{
using System;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using SInnovations.Azure.ServiceFabric.Unity.Abstraction;
public class ActorProxyTypeFactory
{
/// <summary>
/// Creates a new instance of the <see cref="ActorProxyTypeFactory"/> class.
/// </summary>
/// <param name="target"></param>
public ActorProxyTypeFactory(Type target)
{
this.target = target;
}
/// <summary>
/// Creates the proxy registered with specific interceptor.
/// </summary>
/// <returns></returns>
public static T Create<T>(IActorDeactivationInterception deactivation, params object[] args)
{
return (T)new ActorProxyTypeFactory(typeof(T)).Create(new object[] { deactivation }.Concat(args).ToArray());
}
public static Type CreateType<T>()
{
return new ActorProxyTypeFactory(typeof(T)).CreateType();
}
/// <summary>
/// Creates the proxy registered with specific interceptor.
/// </summary>
/// <returns></returns>
public object Create(object[] args)
{
BuidAssembly();
BuildType();
InterceptAllMethods();
Type proxy = this.typeBuilder.CreateType();
return Activator.CreateInstance(proxy, args);
}
public Type CreateType()
{
BuidAssembly();
BuildType();
InterceptAllMethods();
Type proxy = this.typeBuilder.CreateType();
return proxy;
// return Activator.CreateInstance(proxy, args);
}
/// <summary>
/// Builds a dynamic assembly with <see cref="AssemblyBuilderAccess.RunAndSave"/> mode.
/// </summary>
/// <returns></returns>
public void BuidAssembly()
{
AssemblyName assemblyName = new AssemblyName("BasicProxy");
AssemblyBuilder createdAssembly = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
// define module
this.moduleBuilder = createdAssembly.DefineDynamicModule(assemblyName.Name);
}
public void BuildType()
{
if (!target.IsPublic)
{
throw new ArgumentException("Actors have to be public defined to proxy them");
}
this.typeBuilder =
this.moduleBuilder.DefineType(target.FullName + "Proxy", TypeAttributes.Class | TypeAttributes.Public, target);
this.fldInterceptor = this.typeBuilder.DefineField("interceptor", typeof(IActorDeactivationInterception), FieldAttributes.Private);
foreach (var constructor in target.GetConstructors())
{
// Type[] parameters = new Type[1];
ParameterInfo[] parameterInfos = constructor.GetParameters();
Type[] parameters = new Type[parameterInfos.Length + 1];
parameters[0] = typeof(IActorDeactivationInterception);
for (int index = 1; index <= parameterInfos.Length; index++)
{
parameters[index] = parameterInfos[index - 1].ParameterType;
}
ConstructorBuilder constructorBuilder =
typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, parameters);
for (int argumentIndex = 0; argumentIndex < parameters.Length; argumentIndex++)
constructorBuilder.DefineParameter(
argumentIndex + 1,
ParameterAttributes.None,
$"arg{argumentIndex}");
ILGenerator generator = constructorBuilder.GetILGenerator();
generator.Emit(OpCodes.Ldarg_0);
for (int index = 1; index < parameters.Length; index++)
{
generator.Emit(OpCodes.Ldarg, index + 1);
}
generator.Emit(OpCodes.Call, constructor);
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Ldarg_1);
generator.Emit(OpCodes.Stfld, fldInterceptor);
generator.Emit(OpCodes.Ret);
}
}
/// <summary>
/// Builds a type in the dynamic assembly, if already the type is not created.
/// </summary>
/// <returns></returns>
public void InterceptAllMethods()
{
const MethodAttributes targetMethodAttributes =
MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig;
var methodInfo = target.GetMethod("OnDeactivateAsync", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.FlattenHierarchy);
{
if (methodInfo.IsVirtual)
{
Type[] paramTypes = GetParameterTypes(methodInfo.GetParameters());
MethodBuilder methodBuilder =
typeBuilder.DefineMethod(methodInfo.Name, targetMethodAttributes, methodInfo.ReturnType, paramTypes);
ILGenerator ilGenerator = methodBuilder.GetILGenerator();
ilGenerator.Emit(OpCodes.Ldarg_0);
ilGenerator.Emit(OpCodes.Ldfld, fldInterceptor);
ilGenerator.Emit(OpCodes.Call, typeof(IActorDeactivationInterception).GetMethod("Intercept"));
ilGenerator.Emit(OpCodes.Ldarg_0);
ilGenerator.Emit(OpCodes.Call, methodInfo);
ilGenerator.Emit(OpCodes.Ret);
return;
}
}
}
private Type[] GetParameterTypes(ParameterInfo[] parameterInfos)
{
Type[] parameters = new Type[parameterInfos.Length];
int index = 0;
foreach (var parameterInfo in parameterInfos)
{
parameters[index++] = parameterInfo.ParameterType;
}
return parameters;
}
private TypeBuilder typeBuilder;
private ModuleBuilder moduleBuilder;
private readonly Type target;
private FieldInfo fldInterceptor;
}
}
OnActorDeactivateInterceptor.cs
namespace SInnovations.Azure.ServiceFabric.Unity.Actors
{
using Microsoft.Practices.Unity;
using SInnovations.Azure.ServiceFabric.Unity.Abstraction;
public class OnActorDeactivateInterceptor : IActorDeactivationInterception
{
private readonly IUnityContainer container;
public OnActorDeactivateInterceptor(IUnityContainer container)
{
this.container = container;
}
public void Intercept()
{
this.container.Dispose();
}
}
}
UnityFabricExtensions.cs
namespace SInnovations.Azure.ServiceFabric.Unity
{
using System;
using System.Fabric;
using Microsoft.Practices.Unity;
using Microsoft.ServiceFabric.Actors;
using SInnovations.Azure.ServiceFabric.Unity.Abstraction;
using SInnovations.Azure.ServiceFabric.Unity.Actors;
public static class UnityFabricExtensions
{
public static IUnityContainer WithFabricContainer(this IUnityContainer container)
{
return container.WithFabricContainer(c => FabricRuntime.Create());
}
public static IUnityContainer WithFabricContainer(this IUnityContainer container, Func<IUnityContainer,FabricRuntime> factory)
{
container.RegisterType<FabricRuntime>(new ContainerControlledLifetimeManager(), new InjectionFactory(factory));
return container;
}
public static IUnityContainer WithActor<TActor>(this IUnityContainer container) where TActor : ActorBase
{
if (!container.IsRegistered<IActorDeactivationInterception>())
{
container.RegisterType<IActorDeactivationInterception, OnActorDeactivateInterceptor>(new HierarchicalLifetimeManager());
}
container.RegisterType(typeof(TActor), ActorProxyTypeFactory.CreateType<TActor>(),new HierarchicalLifetimeManager());
container.Resolve<FabricRuntime>().RegisterActorFactory(() => {
try {
var actor = container.CreateChildContainer().Resolve<TActor>();
return actor;
}
catch (Exception ex)
{
throw;
}
});
return container;
}
public static IUnityContainer WithStatelessFactory<TFactory>(this IUnityContainer container, string serviceTypeName) where TFactory : IStatelessServiceFactory
{
if (!container.IsRegistered<TFactory>())
{
container.RegisterType<TFactory>(new ContainerControlledLifetimeManager());
}
container.Resolve<FabricRuntime>().RegisterStatelessServiceFactory(serviceTypeName, container.Resolve<TFactory>());
return container;
}
public static IUnityContainer WithStatefulFactory<TFactory>(this IUnityContainer container, string serviceTypeName) where TFactory : IStatefulServiceFactory
{
if (!container.IsRegistered<TFactory>())
{
container.RegisterType<TFactory>(new ContainerControlledLifetimeManager());
}
container.Resolve<FabricRuntime>().RegisterStatefulServiceFactory(serviceTypeName, container.Resolve<TFactory>());
return container;
}
public static IUnityContainer WithService<TService>(this IUnityContainer container, string serviceTypeName)
{
container.Resolve<FabricRuntime>().RegisterServiceType(serviceTypeName, typeof(TService));
return container;
}
}
}
I know this is old but for documentations' sake DI is now supported in the Reliable Actor framework just like you would expect.
public class ActorOne : Actor<MyActorState>, IMyActor{
private readonly IDependency _dependency;
public ActorOne(IDependency dependency)
{
_dependency = dependency;
}}
And then you register the Actor with its dependency with the Service Fabric like this:
using (FabricRuntime fRuntime = FabricRuntime.Create()){
fRuntime.RegisterActor(() => new ActorOne(new MyDependency());
Thread.Sleep(Timeout.Infinite);}
Having had a bit of a dig-around in this area with dotPeek a while back (trying to resolve actors from an Autofac lifetime scope per-invocation), I think the trick is to create your own implementation of StatelessActorServiceFactory, and your own extension method to register the actor with it. Although the factory class is marked as internal, its interface (IStatelessServiceFactory) and the service type it creates (StatelessActorServiceInstance) are both public. Unfortunately, it doesn't look like StatelessActorServiceInstance was designed to be extensible (I'm hoping this is just an oversight).
Unfortunately, it looks like WcfActorCommunicationProvider is also marked as internal so you'll pretty much have to create your own pipeline from scratch:
Implement your own IStatelessServiceFactory
Implement your own IStatelessServiceInstance, IActorService
Implement your own IActorCommunicationProvider
Implement your own IActorHost
Doesn't really seem worth the effort anymore, does it? :-/
That's where I gave up for now. I don't think it's worth trying to roll-your-own for now given the relative immaturity of the public API, since if this sort of functionality will show up at all, they'll probably do so in a way that'll break anything your implement yourself.
Why not just use some root element field in actor, and resolve it from container with injected dependencies in Actor's constructor? If this is a bad decision, please explain why:
public class StatelessActor2 : Actor, IStatelessActor2
{
private ConfiguredContainer _container;
private IRootElement _rootElement;
public StatelessActor2()
{
_container = new ConfiguredContainer(); //... container is configured in it's constructor
_rootElement = _container.Resolve<IRootElement>();
}
public async Task<string> DoWorkAsync()
{
// Working with a RootElement with all dependencies are injected..
return await Task.FromResult(_rootElement.WorkingWithInjectedStuff());
}
}
If you're using Autofac, they have a specific integration package for that:
https://alexmg.com/introducing-the-autofac-integration-for-service-fabric/
https://www.nuget.org/packages/Autofac.ServiceFabric/
In short, registration is performed using ActorRuntime.RegisterActorAsync / ServiceRuntime.RegisterServiceAsync as you would expect. However the more problematic part, namely object release, is automatically handled in the OnDeactivateAsync / OnCloseAsync / OnAbort overrides using a dynamic proxy. Proper lifetime scoped is maintained as well.
At the time of writing it's still in Alpha though (just released last month).
#abatishchev I think you are referring to the Service-Locator antipattern. Both Dependency Injection and Service-Locator are variations of Inversion of Control.
https://www.martinfowler.com/articles/injection.html
Related
I have a method which accepts a list of domain events which implement the interface IDomainEvent. What I'm trying to do is get the underlying type of the IDomainEvent and then use IServiceProvider to get a service matching the underlying system type.
For example, this works;
TicketCreatedEvent event = new TicketCreatedEvent();
var service = _serviceProvider.GetService(typeof(IEventHandler<TicketCreatedEvent>));
// Where _serviceProvider is ASP.NET Cores standard DI provider.
But this doesn't as the event object is created as an interface rather than it's concrete type.
IDomainEvent event = new TicketCreatedEvent();
var service = _serviceProvider.GetService(typeof(IEventHandler<TicketCreatedEvent>));
I know I can retrieve the underlying type by using event.GetType().UnderlyingSystemType but I cannot figure out how to then use this within the _serviceProvider.GetService(), I thought I could have done the following, but it isn't valid;
IDomainEvent event = new TicketCreatedEvent();
Type type = event.GetType().UnderlyingSystemType;
var service = _serviceProvider.GetService(typeof(IEventHandler<type>));
Any advice on how to do this would be appreciated.
Sorry, it seems I missed some important information out of my question.
In my example above, the event is created just before the _serviceProvider is used, by in reality the event is passed to a method on an EventRaiser object, like this;
public static Raise<T>(T args) {
var service = (IEventHandler<T>) _locator.GetService(typeof(IEventHandler<T>));
}
TicketCreatedEvent event = new TicketCreatedEvent();
Raise(event); // Works
IDomainEvent event = new TicketCreatedEvent();
Raise(event); // Doesn't work as it cannot locate the service
Where T is created using the interface, the service cannot be located, it only works if T is directly of the concrete implementation.
To help solving the problem, here is my complete DomainEventRaiser class. There are two important methods, the first is Raise', which will raise an event right away without being deferred. The second isRaisedDeferredwhich accepts a list of events and handles them,RaisedDeferred` will be called when events need to be deferred, such as after a domain object has been persists.
public class DomainEventsRaiser
{
[ThreadStatic] //so that each thread has its own callbacks
private static List<Delegate> _actions;
// ASP.NET Core DI Service Provider
private static IServiceProvider _locator;
/// <summary>
/// Lets the event raiser know what DI provider to use to find event handlers
/// </summary>
/// <param name="provider"></param>
public static void RegisterProvider(IServiceProvider provider)
{
_locator = provider;
}
public static void Register2<T>(Action<T> callback) where T : IDomainEvent
{
if (_actions == null)
{
_actions = new List<Delegate>();
}
_actions.Add(callback);
}
public static void ClearCallbacks()
{
_actions = null;
}
/// <summary>
/// Accepts a list of events, usually deferred events
/// </summary>
/// <param name="events">list of events to handle</param>
public static void RaiseDeferred(IList<IDomainEvent> events)
{
if (events != null)
{
foreach (IDomainEvent ev in events)
{
Type eventType = ev.GetType().UnderlyingSystemType;
Type genericHandlerType = typeof(IEventHandler<>);
Type constructedHandlerType = genericHandlerType.MakeGenericType(eventType);
var service = _locator.GetService(constructedHandlerType);
constructedHandlerType.GetMethod("Handle").Invoke(service, null);
if (service != null)
{
service.Handle(args); // Cannot resolve symbol 'Handle'
}
}
}
}
/// <summary>
/// Handles an event right away
/// </summary>
/// <param name="args">event arguments</param>
/// <typeparam name="T">the event to handle</typeparam>
public static void Raise<T>(T args) where T : IDomainEvent
{
if (_locator != null)
{
var service = (IEventHandler<T>) _locator.GetService(typeof(IEventHandler<T>));
if (service != null)
{
service.Handle(args);
}
}
if (_actions != null)
{
foreach (var action in _actions)
{
if (action is Action<T>)
{
((Action<T>) action)(args);
}
}
}
}
}
You can probably do something like this:
IDomainEvent #event = new TicketCreatedEvent();
Type eventType = #event.GetType().UnderlyingSystemType;
Type genericHandlerType = typeof(IEventHandler<>);
Type constructedHandlerType = genericHandlerType.MakeGenericType(eventType);
var service = _serviceProvider.GetService(constructedHandlerType);
I assume you're registering your handlers in Startup.cs like:
services.AddTransient<IEventHandler<TicketCreatedEvent>, TicketCreatedEventHandler>();
For more info, see How to: Examine and Instantiate Generic Types with Reflection.
I have a following code:
public class Temp<T, TMetadata>
{
[ImportMany]
private IEnumerable<Lazy<T, TMetadata>> plugins;
public Temp(string path)
{
AggregateCatalog aggregateCatalog = new AggregateCatalog();
aggregateCatalog.Catalogs.Add(new DirectoryCatalog(path));
CompositionContainer container = new CompositionContainer(aggregateCatalog);
container.ComposeParts(this);
}
public T GetPlugin(Predicate<TMetadata> predicate)
{
Lazy<T, TMetadata> pluginInfo;
try
{
pluginInfo = plugins.SingleOrDefault(p => predicate(p.Metadata));
}
catch
{
// throw some exception
}
if (pluginInfo == null)
{
// throw some exception
}
return Clone(pluginInfo.Value); // -> this produces errors
}
}
I have a single object of Temp and I call GetPlugin() from multiple threads. Sometimes I face strange composition errors, which I didn't find a way to reproduce. For example:
"System.InvalidOperationException: Stack empty.
at System.Collections.Generic.Stack`1.Pop()
at System.ComponentModel.Composition.Hosting.ImportEngine.TrySatisfyImports(PartManager partManager, ComposablePart part, Boolean shouldTrackImports)
at System.ComponentModel.Composition.Hosting.ImportEngine.SatisfyImports(ComposablePart part)
at System.ComponentModel.Composition.Hosting.CompositionServices.GetExportedValueFromComposedPart(ImportEngine engine, ComposablePart part, ExportDefinition definition)
at System.ComponentModel.Composition.Hosting.CatalogExportProvider.GetExportedValue(CatalogPart part, ExportDefinition export, Boolean isSharedPart)
at System.ComponentModel.Composition.ExportServices.GetCastedExportedValue[T](Export export)
at System.Lazy`1.CreateValue()
at System.Lazy`1.LazyInitValue()
at Temp`2.GetPlugin(Predicate`1 predicate)..."
What could be a reason and how to cure this code?
The CompositionContainer class has a little-known constructor which accepts an isThreadSafe parameter (which defaults to false for performance reasons). If you'll create your container with this value set to true, I believe your problem will be solved:
CompositionContainer container = new CompositionContainer(aggregateCatalog, true);
On a side note, unrelated to the original question, instead of calling Clone() on the plugin, you can use an export factory instead - this way you don't have to implement your own clone method, as MEF will create a new instance for you.
If you want to get a list of available Exports for a matching Import type, you don't need to use the (problematic) container.ComposeParts(this);
You can do something more like:
var pluginsAvailable = container.GetExports<T>().Select(y => y.Value).ToArray();
And that will give you an array of available instances, without all the threading issues that plague MEF.
I've been working on something like this today... please excuse the code dump:
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading;
namespace PluginWatcher
{
/// <summary>
/// Watch for changes to a plugin directory for a specific MEF Import type.
/// <para>Keeps a list of last seen exports and exposes a change event</para>
/// </summary>
/// <typeparam name="T">Plugin type. Plugins should contain classes implementing this type and decorated with [Export(typeof(...))]</typeparam>
public interface IPluginWatcher<T> : IDisposable
{
/// <summary>
/// Available Exports matching type <typeparamref name="T"/> have changed
/// </summary>
event EventHandler<PluginsChangedEventArgs<T>> PluginsChanged;
/// <summary>
/// Last known Exports matching type <typeparamref name="T"/>.
/// </summary>
IEnumerable<T> CurrentlyAvailable { get; }
}
/// <summary>
/// Event arguments relating to a change in available MEF Export types.
/// </summary>
public class PluginsChangedEventArgs<T>: EventArgs
{
/// <summary>
/// Last known Exports matching type <typeparamref name="T"/>.
/// </summary>
public IEnumerable<T> AvailablePlugins { get; set; }
}
/// <summary>
/// Watch for changes to a plugin directory for a specific MEF Import type.
/// <para>Keeps a list of last seen exports and exposes a change event</para>
/// </summary>
/// <typeparam name="T">Plugin type. Plugins should contain classes implementing this type and decorated with [Export(typeof(...))]</typeparam>
public class PluginWatcher<T> : IPluginWatcher<T>
{
private readonly object _compositionLock = new object();
private FileSystemWatcher _fsw;
private DirectoryCatalog _pluginCatalog;
private CompositionContainer _container;
private AssemblyCatalog _localCatalog;
private AggregateCatalog _catalog;
public event EventHandler<PluginsChangedEventArgs<T>> PluginsChanged;
protected virtual void OnPluginsChanged()
{
var handler = PluginsChanged;
if (handler != null) handler(this, new PluginsChangedEventArgs<T> { AvailablePlugins = CurrentlyAvailable });
}
public PluginWatcher(string pluginDirectory)
{
if (!Directory.Exists(pluginDirectory)) throw new Exception("Can't watch \"" + pluginDirectory + "\", might not exist or not enough permissions");
CurrentlyAvailable = new T[0];
_fsw = new FileSystemWatcher(pluginDirectory, "*.dll");
SetupFileWatcher();
try
{
_pluginCatalog = new DirectoryCatalog(pluginDirectory);
_localCatalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
_catalog = new AggregateCatalog();
_catalog.Catalogs.Add(_localCatalog);
_catalog.Catalogs.Add(_pluginCatalog);
_container = new CompositionContainer(_catalog, false);
_container.ExportsChanged += ExportsChanged;
}
catch
{
Dispose(true);
throw;
}
ReadLoadedPlugins();
}
private void SetupFileWatcher()
{
_fsw.NotifyFilter = NotifyFilters.Attributes | NotifyFilters.CreationTime | NotifyFilters.FileName |
NotifyFilters.LastAccess | NotifyFilters.LastWrite | NotifyFilters.Size | NotifyFilters.Security;
_fsw.Changed += FileAddedOrRemoved;
_fsw.Created += FileAddedOrRemoved;
_fsw.Deleted += FileAddedOrRemoved;
_fsw.Renamed += FileRenamed;
_fsw.EnableRaisingEvents = true;
}
private void ExportsChanged(object sender, ExportsChangeEventArgs e)
{
lock (_compositionLock)
{
if (e.AddedExports.Any() || e.RemovedExports.Any()) ReadLoadedPlugins();
}
}
private void ReadLoadedPlugins()
{
CurrentlyAvailable = _container.GetExports<T>().Select(y => y.Value).ToArray();
OnPluginsChanged();
}
private void FileRenamed(object sender, RenamedEventArgs e)
{
RefreshPlugins();
}
void FileAddedOrRemoved(object sender, FileSystemEventArgs e)
{
RefreshPlugins();
}
private void RefreshPlugins()
{
try
{
var cat = _pluginCatalog;
if (cat == null) { return; }
lock (_compositionLock)
{
cat.Refresh();
}
}
catch (ChangeRejectedException rejex)
{
Console.WriteLine("Could not update plugins: " + rejex.Message);
}
}
public IEnumerable<T> CurrentlyAvailable { get; protected set; }
~PluginWatcher()
{
Dispose(true);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected void Dispose(bool disposing)
{
if (!disposing) return;
var fsw = Interlocked.Exchange(ref _fsw, null);
if (fsw != null) fsw.Dispose();
var plg = Interlocked.Exchange(ref _pluginCatalog, null);
if (plg != null) plg.Dispose();
var con = Interlocked.Exchange(ref _container, null);
if (con != null) con.Dispose();
var loc = Interlocked.Exchange(ref _localCatalog, null);
if (loc != null) loc.Dispose();
var cat = Interlocked.Exchange(ref _catalog, null);
if (cat != null) cat.Dispose();
}
}
}
Can anyone help, I am having problems using the auto-mocking that is available between Ninject and NSubstitute, actually the package is a ninject packaged called Ninject.MockingKernel.NSubstitute which should allow me to use Ninject to create mocks and return instances with mocks injected.
There seems to be a few examples for Moq and Rhinomocks but I don't see any for NSubstitute.
What I have so far is
this.kernel = new NSubstituteMockingKernel();
var summaryService = this.kernel.GetMock<IMyService>(); // GetMock not available
Anybody using it?
Here are a couple of examples adapted from the source code:
[TestFixture]
public class Tests
{
/// <summary>
/// Mocks are singletons.
/// </summary>
[Test]
public void MocksAreSingletons()
{
using (var kernel = new NSubstituteMockingKernel())
{
var firstReference = kernel.Get<IDummyService>();
var secondReference = kernel.Get<IDummyService>();
firstReference.Should().BeSameAs(secondReference);
}
}
/// <summary>
/// Real objects are created for auto bindable types.
/// </summary>
[Test]
public void RealObjectsAreCreatedForAutoBindableTypes()
{
using (var kernel = new NSubstituteMockingKernel())
{
var instance = kernel.Get<DummyClass>();
instance.Should().NotBeNull();
}
}
/// <summary>
/// Reals objects are singletons.
/// </summary>
[Test]
public void RealObjectsAreSingletons()
{
using (var kernel = new NSubstituteMockingKernel())
{
var instance1 = kernel.Get<DummyClass>();
var instance2 = kernel.Get<DummyClass>();
instance1.Should().BeSameAs(instance2);
}
}
/// <summary>
/// The injected dependencies are actually mocks.
/// </summary>
[Test]
public void TheInjectedDependenciesAreMocks()
{
using (var kernel = new NSubstituteMockingKernel())
{
var instance = kernel.Get<DummyClass>();
instance.DummyService.Do();
instance.DummyService.Received().Do();
}
}
public interface IDummyService
{
void Do();
}
public class DummyClass
{
public DummyClass(IDummyService dummyService)
{
this.DummyService = dummyService;
}
public IDummyService DummyService { get; set; }
}
}
Clearly, I am missing something. I have an MVC application and have installed Ninject 3 and the MVC3 extensions (although I am running MVC4). I have a SiteSettings class that is referenced throughout the project, which looks like this:
public class SiteSettings
{
private static readonly Common.Logging.ILog Logger = Common.Logging.LogManager.GetCurrentClassLogger();
private static ObservableDictionary<string, string> settings;
private static bool Initialized = false;
private static DataPersister persister;
public static void Initialize()
{
if (Initialized) throw new InvalidOperationException("The SiteSettings object has already been initialized.");
persister = new DataPersister();
using (var u = persister.UnitOfWorkFactory.GetUnitOfWork())
{
var settingsList = u.SiteSettings.GetAll();
settings = new ObservableDictionary<string, string>(settingsList.ToDictionary(key => key.SiteSettingName, value => value.SiteSettingValue));
settings.OnChange += new kvpChangeEvent<string, string>(settings_OnChange);
}
Initialized = true;
}
static void settings_OnChange(object sender, odKVPChangeEventArgs<string, string> e)
{
using (var u = persister.UnitOfWorkFactory.GetUnitOfWork())
{
var setting = u.SiteSettings.GetByName(e.Key);
setting.SiteSettingValue = e.Value;
u.SiteSettings.Update(setting);
u.Save();
Logger.Info(i => i("Changed the '{0}' site setting from '{1}' to '{2}'.", e.Key, e.OldValue, e.Value));
}
}
private static int _ItemsPerPage;
public static int ItemsPerPage
{
get
{
return _ItemsPerPage;
}
set
{
_ItemsPerPage = value;
settings["itemsPerPage"] = value.ToString();
}
}
private static int _SessionLifeInMinutes;
public static int SessionLifeInMinutes
{
get
{
return _SessionLifeInMinutes;
}
set
{
_SessionLifeInMinutes = value;
settings["sessionLifeInMinutes"] = value.ToString();
}
}
private static string _DateFormat;
public static string DateFormat
{
get
{
return _DateFormat;
}
set
{
_DateFormat = value;
settings["defaultDateFormat"] = value;
}
}
}
I built a data persistence object like so:
public class DataPersister
{
public IUnitOfWorkFactory UnitOfWorkFactory { get; set; }
}
... and I have my NinjectWebCommon.cs looks like this:
public static class NinjectWebCommon
{
private static readonly Bootstrapper bootstrapper = new Bootstrapper();
/// <summary>
/// Starts the application
/// </summary>
public static void Start()
{
DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
bootstrapper.Initialize(CreateKernel);
}
/// <summary>
/// Stops the application.
/// </summary>
public static void Stop()
{
bootstrapper.ShutDown();
}
/// <summary>
/// Creates the kernel that will manage your application.
/// </summary>
/// <returns>The created kernel.</returns>
private static IKernel CreateKernel()
{
var kernel = new StandardKernel();
kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
RegisterServices(kernel);
return kernel;
}
/// <summary>
/// Load your modules or register your services here!
/// </summary>
/// <param name="kernel">The kernel.</param>
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<IUnitOfWork>().To<NHUnitOfWork>();
kernel.Bind<IUnitOfWorkFactory>().To<NHUnitOfWorkFactory>();
}
}
It seems to me I've met all my requirements for dependency injection. My Global.asax.cs Application_Start() looks like this:
protected void Application_Start()
{
ViewEngines.Engines.Clear();
ViewEngines.Engines.Add(new MonoRazorViewEngine());
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
ControllerBuilder.Current.DefaultNamespaces.Add("MyApplication.Application.Controllers");
Initialize.Security();
SiteSettings.Initialize();
}
...and yet, my SiteSettings class always has a null IUnitOfWorkFactory when I try to collect the data I need.
What am I doing wrong? Everything seems to be as all the examples suggest it should be, but I get no love.
UPDATE
Using Bassam Mehanni's advice, I rewrote my DataPersister class to look like this:
public class DataPersister
{
private IUnitOfWorkFactory UnitOfWorkFactory;
public DataPersister(IUnitOfWorkFactory unitOfWorkFactory)
{
UnitOfWorkFactory = unitOfWorkFactory;
}
public IUnitOfWork GetUnitOfWork()
{
return UnitOfWorkFactory.GetUnitOfWork();
}
}
...but of course now my SiteSettings class complains about my parameterless constructor. What should I do about that?
UPDATE 2
Ok, continuing on, I rewrote my DataPersister class like so:
public class DataPersister
{
private static readonly Common.Logging.ILog Logger = Common.Logging.LogManager.GetCurrentClassLogger();
private IUnitOfWorkFactory UnitOfWorkFactory { get; set; }
public IUnitOfWork GetUnitOfWork()
{
return UnitOfWorkFactory.GetUnitOfWork();
}
[Inject]
public DataPersister(IUnitOfWorkFactory factory)
{
Logger.Info("Injected constructor called");
UnitOfWorkFactory = factory;
}
public DataPersister()
{
Logger.Info("Parameterless constructor called");
}
}
then I rewrote my SiteSettings class like so:
public class SiteSettings
{
private static readonly Common.Logging.ILog Logger = Common.Logging.LogManager.GetCurrentClassLogger();
private ObservableDictionary<string, string> settings;
private DataPersister persister;
private SiteSettings()
{
persister = new DataPersister();
using (var u = persister.GetUnitOfWork())
{
var settingsList = u.SiteSettings.GetAll();
settings = new ObservableDictionary<string, string>(settingsList.ToDictionary(key => key.SiteSettingName, value => value.SiteSettingValue));
settings.OnChange += new kvpChangeEvent<string, string>(settings_OnChange);
}
}
private static SiteSettings instance;
public static SiteSettings Instance
{
get
{
if (instance == null)
{
instance = new SiteSettings();
}
return instance;
}
}
private void settings_OnChange(object sender, odKVPChangeEventArgs<string, string> e)
{
using (var u = persister.GetUnitOfWork())
{
var setting = u.SiteSettings.GetByName(e.Key);
setting.SiteSettingValue = e.Value;
u.SiteSettings.Update(setting);
u.Save();
Logger.Info(i => i("Changed the '{0}' site setting from '{1}' to '{2}'.", e.Key, e.OldValue, e.Value));
}
}
private int _ItemsPerPage;
public int ItemsPerPage
{
get
{
return _ItemsPerPage;
}
set
{
_ItemsPerPage = value;
settings["itemsPerPage"] = value.ToString();
}
}
private int _SessionLifeInMinutes;
public int SessionLifeInMinutes
{
get
{
return _SessionLifeInMinutes;
}
set
{
_SessionLifeInMinutes = value;
settings["sessionLifeInMinutes"] = value.ToString();
}
}
private string _DateFormat;
public string DateFormat
{
get
{
return _DateFormat;
}
set
{
_DateFormat = value;
settings["defaultDateFormat"] = value;
}
}
}
Shouldn't this work? because it doesn't. The DataPersister class always gets called with the parameterless constructor. My kernel binding looks like this:
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<IUnitOfWork>().To<NHUnitOfWork>();
kernel.Bind<IUnitOfWorkFactory>().To<NHUnitOfWorkFactory>();
}
Is there something else I am missing? This is getting very frustrating.
Static classes that depencend on none static classes is something you shouldn't do when using an IoC container. Instead you should create a none static class with a singleton lifetime.
Make your SiteSettings class none static.
Inject all dependencies e.g. IUnitOfWorkFactory into SiteSettings using constructor injection
Create a binding in singleton scope for SiteSettings
Get an instance of SiteSettings wherever you need access unsing constructor injection.
Example:
public class SiteSettings {
public SiteSettings(IUnitOfWorkFactory uowFactory) { .... }
....
}
public class INeedToAccessSiteSettings
{
public INeedToAccessSiteSettings(SiteSettings siteSettings) { .... }
}
kenrel.Bind<SiteSettings>().ToSelf().InSingletonScope();
Typically ninject will inject your service in a constructor or something, it doesn't magically turn all your interfaces to object instances at run time
e.g.:
public class MyController : Controller
{
private IServiceThatINeed _serviceThatINeed;
public MyController(IServiceThatINeed serviceThatINeed)
{
_serviceThatINeed = _serviceThatINeed;
}
}
in this case since you registered your kernel instance, mvc knows how to resolve this dependence and will pass an instance of an object that implement IServiceThatINeed (assuming that you told ninject how to resolve this dependency.
Now there might be instance where you will need to get a service without it being injected in a constructor by the mvc framework, in these instances (like the one you have here), you will need to use ServiceLocator
e.g.:
var myService = ServiceLocator.Current.GetInstance<IServiceThatINeed>()
to use the ServiceLocator, you need to add a reference to Microsoft.Practices.ServiceLocation
Hope that helps!
We have started using Ninject version 2 as our IoC container along with the extension for resolving by naming conventions. We are also using log4net for our logging.
What I would like is for Ninject to log all the dependencies it has found and what will resolve them to, preferably on the application start-up.
I have found the logging extension, but can't find documentation or examples on how to use it to get this.
Edit:
Since it was requested here is the class that logs the default bindings on startup, using log4net
public class DefaultBindingGeneratorWithLogging : IBindingGenerator
{
private readonly IKernel kernel;
/// <summary>
/// Initializes a new instance of the <see cref="DefaultBindingGeneratorWithLogging"/> class.
/// </summary>
/// <param name="kernel">The kernel.</param>
public DefaultBindingGeneratorWithLogging(IKernel kernel)
{
this.kernel = kernel;
}
/// <summary>
/// Creates the bindings for a type.
/// </summary>
/// <param name="type">The type for which the bindings are created.</param>
/// <param name="bindingRoot">The binding root that is used to create the bindings.</param>
/// <returns>
/// The syntaxes for the created bindings to configure more options.
/// </returns>
public IEnumerable<IBindingWhenInNamedWithOrOnSyntax<object>> CreateBindings(Type type, IBindingRoot bindingRoot)
{
if (type.IsInterface || type.IsAbstract)
{
yield break;
}
Type interfaceForType = type.GetInterface("I" + type.Name, false);
if (interfaceForType == null)
{
yield break;
}
var log = kernel.Get<ILog>();
if (!(kernel.GetBindings(interfaceForType).Any()))
{
bindingRoot.Bind(interfaceForType).To(type).InTransientScope();
if (log.IsInfoEnabled && !String.IsNullOrWhiteSpace(interfaceForType.FullName))
{
log.InfoFormat("Mapping {0} -> {1}", type.FullName, interfaceForType.FullName);
}
}
else
{
log.InfoFormat("Didn't map {0} -> {1} mapping already exists", type.FullName, interfaceForType.FullName);
}
}
}
You can probably achieve what you are trying to do by creating your own instance of 'ActivationStrategy'. Here is one that I was using to monitor activation / deactivation:
public class MyMonitorActivationStrategy : ActivationStrategy
{
private ILogger _logger;
public override void Activate(Ninject.Activation.IContext context, Ninject.Activation.InstanceReference reference)
{
if(reference.Instance is ILogger)
{
_logger = (ILogger)reference.Instance;
}
_logger.Debug("Ninject Activate: " + reference.Instance.GetType());
base.Activate(context, reference);
}
public override void Deactivate(Ninject.Activation.IContext context, Ninject.Activation.InstanceReference reference)
{
_logger.Debug("Ninject DeActivate: " + reference.Instance.GetType());
base.Deactivate(context, reference);
}
}
You wire this when you create your kernel.
protected override IKernel CreateKernel()
{
var kernel = new StandardKernel();
kernel.Components.Add<IActivationStrategy, MyMonitorActivationStrategy>();
kernel.Load<AppModule>();
return kernel;
}
Hope this helps.
Bob