Any Ninject experts in the house? :)
I've recently been trying to convert my WCF Service Application and Windows Forms Client Application from Castle Windsor dependency injection to Ninject.
All has gone fine on the Win Forms side, but I am encountering issues on the WCF side of things. I have learned so far I believe I need to WCF extensions available for Ninject in order to use DI with WCF which I have done and referenced but still experiencing an issue I believe when my service is attempted to be resolved:
System.InvalidOperationException: The type 'WcfMemberService', provided as the Service attribute value in the ServiceHost directive, or provided in the configuration element system.serviceModel/serviceHostingEnvironment/serviceActivations could not be found.
The code I have which is what I thought to be correct to access just for instance my WcfMemberService is as follows:
ServiceModule.cs:
public class ServiceModule : NinjectModule
{
private IKernel _parentContainer;
public ServiceModule(IKernel container)
{
this._parentContainer = container;
}
public override void Load()
{
Bind<IDataContextProvider>().To<DataContextProvider>()
.WithConstructorArgument("connectionString", ConfigurationManager.ConnectionStrings["connectionString"].ConnectionString);
Bind(typeof(IRepository<>)).To(typeof(Repository<>));
Bind<IServiceLocator>().ToConstant(new NinjectServiceLocator(_parentContainer));
Bind<IUserService>().To<UserService>();
// ** WCF Services **
Bind<Business.Common.Wcf.Services.Contracts.IMemberServiceContract>().To<Business.Common.Wcf.Services.MemberService>().InSingletonScope().Named("WcfMemberService");
}
}
The assumption I made is when converting over from my working Castle Windsor configuration is that Named() should be the same entry which is featured in the declaration of your WCF .svc file. So I have done that as follows:
<%# ServiceHost Language="C#" Service="WcfMemberService" Factory="Ninject.Extensions.Wcf.NinjectServiceHostFactory" %>
Pretty simple, I have taken this approach from the TimeService example solution featured on the Ninject Wcf Extensions GitHub page here by the way.
Can anyone see what I have done wrong here and why "WcfMemberService" would not be resolving? It is bound to be "WcfMemberService" in the Kernel and referenced in the #ServiceHost declaration. I can't see what else could be wrong. This is exactly the same as how I declare it in Castle Windsor, except for roughly different syntax, but both use Named() and both ref that name in the Service part of the .svc file.
*Update* I have discovered if I do not use the Named() approach, and simply set my service in # ServiceHost declaration as Business.Common.Wcf.Services.MemberService, Business.Common.Wcf.Services it works. But I am still stumped as to why I can't use Named services. Thanks.
By the way, my Ninject module is loaded via Global.asax.cs in this fashion:
public class Global : NinjectWcfApplication
{
#region Overrides of NinjectWcfApplication
/// <summary>
/// Creates the kernel that will manage your application.
/// </summary>
/// <returns>The created kernel.</returns>
protected override IKernel CreateKernel()
{
// config to reside in executing directory
log4net.Config.XmlConfigurator.Configure(new FileInfo("log4net.config"));
var _container = new StandardKernel();
_container.Load(new ServiceModule(_container));
//_container.Load(new Log4netModule());
ServiceLocator.SetLocatorProvider(() => _container.Get<IServiceLocator>());
return _container;
}
#endregion
}
The .Named(string) syntax is used in conditional binding. For example, if you have
Bind<IService1>().To<MyService>().Named("MyServiceImpl");
Bind<IService1>().To<DefaultService();
Then DefaultService will be injected as the default unless you have something like the following:
class MyForm([Named("MyServiceImpl")] IService1 service){...}
or
kernel.Get<IService1>(metadata => metadata.Name == "MyServiceImpl");
or
kernel.Get<IService1>("MyServiceImpl");
If you do not have a default binding for the type, and you only have the conditional named binding, then you will get an activation exception when you try to create an instance.
-Ian
Related
Update 09.08.2018
Unity is being developed here but I haven't had the time to test how it plays with the ASP.NET Core framework.
Update 15.03.2018
This solution is for the specific problem of using ASP.NET Core v1 with Unity while using the .NET Framework 4.5.2 NOT the .NET Core Framework. I had to use this setup since I needed some .Net 4.5.2 DLLs but for anyone starting afresh I would not recommend this approach. Also Unity is not being developed any further (to my knowlage) so I would recommend using the Autofac Framework for new projects. See this Post for more info on how to do that.
Intro
I am building a Web Application using ASP.NET with MVC. This Application depends on certain services (a WCF Service a Datastore service etc). Now to keep things nice and decoupled I want to use a DI (Dependecy Injection) Framework, specifically Unity.
Initial Research
I found this blog post but sadly its not working. The idea though is nice. It basically says that you should not register all the services registered in the ServiceCollection into your own container, but rather reference the default ServiceProvider. So. if something needs to be resolved the default ServiceProvider is called and in case it has no resolution the type will be resolved using your custom UnityContainer.
The Problems
MVC always tries to resolve the Controller with the default ServiceProvider. Also, I noticed that even if the Controller would get resolved correctly, I can never "mix" Dependencies. Now, if I want to use one of my Services but also an IOptions interface from ASP the class can never be resolved because not one of those two containers has resolutions for both types.
What I need
So to recap I need the following things:
A setup where I dont need to copy ASP.NET Dependencies into my UnityContainer
A container which can resolve my MVC Controllers
A container which can resolve "mixed" Dependencies
EDIT:
So the question is how can I achieve these points ?
Environment
project.json:
So after some research I came up with the following solutions to my problems:
Use Unity with ASP
To be able to use Unity with ASP I needed a custom IServiceProvider (ASP Documentation) so I wrote a wrapper for the IUnityContainer which looks like this
public class UnityServiceProvider : IServiceProvider
{
private IUnityContainer _container;
public IUnityContainer UnityContainer => _container;
public UnityServiceProvider()
{
_container = new UnityContainer();
}
#region Implementation of IServiceProvider
/// <summary>Gets the service object of the specified type.</summary>
/// <returns>A service object of type <paramref name="serviceType" />.-or- null if there is no service object of type <paramref name="serviceType" />.</returns>
/// <param name="serviceType">An object that specifies the type of service object to get. </param>
public object GetService(Type serviceType)
{
//Delegates the GetService to the Containers Resolve method
return _container.Resolve(serviceType);
}
#endregion
}
Also I had to change the Signature of the ConfigureServices method in my Startup class from this:
public void ConfigureServices(IServiceCollection services)
to this:
public IServiceProvider ConfigureServices(IServiceCollection services)
Now I can return my custom IServiceProvider and it will be used instead of the default one.The full ConfigureServices Method is shown in the Wire up section at the bottom.
Resolving Controllers
I found this blog post. From it I learned that MVC uses an IControllerActivator interface to handle Controller instantiation. So I wrote my own which looks like this:
public class UnityControllerActivator : IControllerActivator
{
private IUnityContainer _unityContainer;
public UnityControllerActivator(IUnityContainer container)
{
_unityContainer = container;
}
#region Implementation of IControllerActivator
public object Create(ControllerContext context)
{
return _unityContainer.Resolve(context.ActionDescriptor.ControllerTypeInfo.AsType());
}
public void Release(ControllerContext context, object controller)
{
//ignored
}
#endregion
}
Now if a Controller class is activated it will be instatiated with my UnityContainer. Therefore my UnityContainer must know how to Resolve any Controller!
Next Problem: Use the default IServiceProvider
Now if I register services such as Mvc in ASP.NET I normally would do it like this:
services.AddMvc();
Now if I use a UnityContainer all the MVC Dependencies could not be Resolved because they aren't Registered. So I can either Register them (like AutoFac) or I can create a UnityContainerExtension. I opted for the Extension and came up with following two clases :
UnityFallbackProviderExtension
public class UnityFallbackProviderExtension : UnityContainerExtension
{
#region Const
///Used for Resolving the Default Container inside the UnityFallbackProviderStrategy class
public const string FALLBACK_PROVIDER_NAME = "UnityFallbackProvider";
#endregion
#region Vars
// The default Service Provider so I can Register it to the IUnityContainer
private IServiceProvider _defaultServiceProvider;
#endregion
#region Constructors
/// <summary>
/// Creates a new instance of the UnityFallbackProviderExtension class
/// </summary>
/// <param name="defaultServiceProvider">The default Provider used to fall back to</param>
public UnityFallbackProviderExtension(IServiceProvider defaultServiceProvider)
{
_defaultServiceProvider = defaultServiceProvider;
}
#endregion
#region Overrides of UnityContainerExtension
/// <summary>
/// Initializes the container with this extension's functionality.
/// </summary>
/// <remarks>
/// When overridden in a derived class, this method will modify the given
/// <see cref="T:Microsoft.Practices.Unity.ExtensionContext" /> by adding strategies, policies, etc. to
/// install it's functions into the container.</remarks>
protected override void Initialize()
{
// Register the default IServiceProvider with a name.
// Now the UnityFallbackProviderStrategy can Resolve the default Provider if needed
Context.Container.RegisterInstance(FALLBACK_PROVIDER_NAME, _defaultServiceProvider);
// Create the UnityFallbackProviderStrategy with our UnityContainer
var strategy = new UnityFallbackProviderStrategy(Context.Container);
// Adding the UnityFallbackProviderStrategy to be executed with the PreCreation LifeCycleHook
// PreCreation because if it isnt registerd with the IUnityContainer there will be an Exception
// Now if the IUnityContainer "magically" gets a Instance of a Type it will accept it and move on
Context.Strategies.Add(strategy, UnityBuildStage.PreCreation);
}
#endregion
}
UnityFallbackProviderStrategy:
public class UnityFallbackProviderStrategy : BuilderStrategy
{
private IUnityContainer _container;
public UnityFallbackProviderStrategy(IUnityContainer container)
{
_container = container;
}
#region Overrides of BuilderStrategy
/// <summary>
/// Called during the chain of responsibility for a build operation. The
/// PreBuildUp method is called when the chain is being executed in the
/// forward direction.
/// </summary>
/// <param name="context">Context of the build operation.</param>
public override void PreBuildUp(IBuilderContext context)
{
NamedTypeBuildKey key = context.OriginalBuildKey;
// Checking if the Type we are resolving is registered with the Container
if (!_container.IsRegistered(key.Type))
{
// If not we first get our default IServiceProvider and then try to resolve the type with it
// Then we save the Type in the Existing Property of IBuilderContext to tell Unity
// that it doesnt need to resolve the Type
context.Existing = _container.Resolve<IServiceProvider>(UnityFallbackProviderExtension.FALLBACK_PROVIDER_NAME).GetService(key.Type);
}
// Otherwise we do the default stuff
base.PreBuildUp(context);
}
#endregion
}
Now if my UnityContainer has no Registration for something it just ask the default Provider for it.
I learned all of this from several different articles
MSDN Unity article
Auto-Mocking Unity Container Extension
Custom Object Factory Unity Extension
The nice thing about this approach is that I can also "mix" Dependencies now. If I need any of my Services AND an IOptions Interface from ASP my UnityContainer will resolve all of these Dependencies and Inject them into my Controller !!! The only thing to remember is that if I use any of my own Dependencies I have to register my Controller class with Unity because the default IServiceProvider can no longer Resolve my Controllers Dependencies.
Finally: Wire up
Now in my project I use different services (ASP Options, MVC with options). To make it all work my ConfigureServices Method looks like this now:
public IServiceProvider ConfigureServices(IServiceCollection services)
{
// Add all the ASP services here
// #region ASP
services.AddOptions();
services.Configure<WcfOptions>(Configuration.GetSection("wcfOptions"));
var globalAuthFilter = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
services.AddMvc(options => { options.Filters.Add(new AuthorizeFilter(globalAuthFilter)); })
.AddJsonOptions
(
options => options.SerializerSettings.ContractResolver = new DefaultContractResolver()
);
// #endregion ASP
// Creating the UnityServiceProvider
var unityServiceProvider = new UnityServiceProvider();
IUnityContainer container = unityServiceProvider.UnityContainer;
// Adding the Controller Activator
// Caution!!! Do this before you Build the ServiceProvider !!!
services.AddSingleton<IControllerActivator>(new UnityControllerActivator(container));
//Now build the Service Provider
var defaultProvider = services.BuildServiceProvider();
// Configure UnityContainer
// #region Unity
//Add the Fallback extension with the default provider
container.AddExtension(new UnityFallbackProviderExtension(defaultProvider));
// Register custom Types here
container.RegisterType<ITest, Test>();
container.RegisterType<HomeController>();
container.RegisterType<AuthController>();
// #endregion Unity
return unityServiceProvider;
}
Since I learned most of what I know about DI in the past week I hope I didnt break any big Pricipal/Pattern if so please tell me!
For ASP.Net Core 2.0, 2.1, 2.2, 3.1 and Unity there is official solution available from Unity authors as NuGet package here: NuGetPackage
Here is Git repository with samples: Git repo
Usage is very simple (from Git repo homepage):
public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseUnityServiceProvider() <---- Add this line
.UseStartup<Startup>()
.Build();
And here is example with Unity DI for ASP.Net Core.
I am using this solution in my ASP.Net Core application and works good.
I'm quite new to IoC frameworks so please excuse the terminology.
So what I have is a MVC project with the Nininject MVC references.
I have other class libarys in my project e.g. Domain layer, I would like to be able to use the Ninject framework in there but all of my bindings are in the NinjectWebCommon.cs under the App_Start folder in the MVC project:
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<IHardwareService>().To<WindowsHardwareService>();
kernel.Bind<IStatusApi>().To<StatusApiController>();
}
Currently in my class library I am using constructor injection but sometime I am having to hardcode the dependencies:
var service = new WindowsHardwareService();
When I would like to be able to do the following:
IKernel kernel = new StandardKernel(.....);
var context = kernel.Get<IHardwareService>();
I have not been doing the following because I do not have any modules?
All of the documentation I have read is mainly aimed at the regular Ninject library and not the MVC version.
What do I need to do, and how can I use the regular Ninject library with the MVC version?
Update
This is what I have tried:
The aim of this is so that each project can load the module and get the current injected interface.
App_Start/NinjectWebCommon.cs (In MVC Project)
private static void RegisterServices(IKernel kernel)
{
var modules = new IoCModules();
var newKernal = modules.GetKernel();
kernel = newKernal;
}
IoCModules.cs (In Project.Ioc project)
public class IoCModules
{
public IKernel GetKernel()
{
var modules = new CoreModule();
return modules.Kernel;
}
}
CoreModule.cs (In Project.IoC.Modules project) <-- This is where all the references to all projects are, this get's around any circular dependency issues.
public class CoreModule : NinjectModule
{
public override void Load()
{
Bind<IHardwareService>().To<WindowsHardwareService>();
Bind<IStatusApi>().To<StatusApiController>();
}
}
But I am currently getting the following:
Error activating IHardwareService
No matching bindings are available, and the type is not self-bindable.
Activation path:
2) Injection of dependency IHardwareService into parameter service of constructor of type DashboardController
1) Request for DashboardController
Suggestions:
1) Ensure that you have defined a binding for IHardwareService.
2) If the binding was defined in a module, ensure that the module has been loaded into the kernel.
3) Ensure you have not accidentally created more than one kernel.
4) If you are using constructor arguments, ensure that the parameter name matches the constructors parameter name.
5) If you are using automatic module loading, ensure the search path and filters are correct.
It seems that you have a lot of questions what needs to be answered here, so I will try to do my best.
Based on your current question I will try to "draw up" a simplified architecture of your current implementation:
Domain layer: The core of your domain, place of your business entities, etc.
Infrastructure layer: This is where your services reside e.g.: WindowsHardwareService
IOC: I tend to call to this as DependencyResolution assembly.
UI: MVC application
Assuming this all above, we can state that your applications Composition Root or Entry point is the UI MVC project. One of the main concepts using a DI Container that is you initalize it in the Composition Root set up/do all your needed bindings and registrations here. The main intention to do it in the entry point is to avoid the Service Locator anti-pattern.
By using a DI Container you don't new() up your class implementations or get the kernel but rather ask for the registered dependency, following the rule of Inversion Of Control or also known as the Hollywood principle.
After the philosphy course, we can finally get to some actual implementation.
Creating an Ninject module: in your IOC assembly, lets call this file as ServiceModule.cs
using Ninject.Modules;
public class ServiceModule : NinjectModule
{
public override void Load()
{
Bind<IHardwareService>().To<WindowsHardwareService>();
Bind<IStatusApi>().To<StatusApiController>();
}
}
This will be the Ninject module that you will register/load in the Composition Root.
Now about the Composition Root: in UI MVC projects NinjectWebCommon.cs
You can have a method that is responsible loading your modules as below.
private static void RegisterServices(IKernel kernel)
{
var modules = new List<INinjectModule>
{
new ServiceModule()
//, new FooModule()
//, new BarModule()
};
kernel.Load(modules);
}
And finally your DashboardController in UI MVC:
public class DashboardController : Controller
{
private readonly IHardwareService _hardwareService;
public DashboardController(IHardwareService hardwareService)
{
_hardwareService = hardwareService;
}
}
At this point, your ask for the registered implementation of IHardwareService in the controllers constructor. The DI Container will do the dirty job and pass you the instance that you can work with later in your controller.
A note about the interfaces: I tend to put these into an own assembly, where I just store the interfaces, e.g.: Project.Domain.Interfaces or Project.Infrastructure.Interfaces where each of these assemblies contain only domain or infrastructure interfaces.
References between assemblies:
To put all these together the UI only references the IOC assembly and the interfaces assembly that containts the interfaces you bound in your Ninject Module.
Summarizing all of the above:
Your classes and interfaces alone by theirselves are just pieces what are getting glued together by the DI container.
Hope I cleared it up a bit.
EDIT: as some good advice that #AndreySarafanov pointed out in comments, if you need different implementations of an interface you ask for in the constructor, you can use a Ninject Factory. For more information you can refer to this answer.
I fail to understand how to probably setup my Ninject IoC container.
I have a Service layer which contains implementations of several services and implementation of my DbContext and ASP.NET Identity like so:
public class IdentityModule : NinjectModule
{
public override void Load()
{
Bind<IUserStore<User, int>>().To<UserService>().InSingletonScope();
Bind<UserManager<User, int>>().ToSelf().InSingletonScope();
Bind<IRoleStore<UserRole, int>>().To<UserRoleService>().InSingletonScope();
Bind<RoleManager<UserRole, int>>().ToSelf().InSingletonScope();
}
}
public class EntityFrameworkModule : NinjectModule
{
public override void Load()
{
Bind<EntityDbContext>().ToSelf();
Bind<ICreateDbModel>().To<DefaultDbModelCreator>();
Bind<IUnitOfWork>().To<EntityDbContext>();
Bind<IWriteEntities>().To<EntityDbContext>();
Bind<IReadEntities>().To<EntityDbContext>();
}
}
These are loaded into my NinjectWebCommen (MVC layer):
private static void RegisterServices(IKernel kernel)
{
var modules = new INinjectModule[]
{
new EntityFrameworkModule(),
new IdentityModule()
};
kernel.Load(modules);
}
Now my question is:
My EntityDbContext should be request scoped, but I am unable to set .InRequestScope() from my service layer. Should this INinjectModule then be moved to the MVC layer instead of lying in the service layer or should I reference Ninject.Web.Common in my service layer? This just seem to be a wrong way since the service layer is not a web-app.
This place where you wire everything together is called the
Composition Root in DI terminology
One of the suggestions is to create a bootstrap for all layers. Check this SO:
Where to locate Ninject modules in a multi-tier application
This is not the best answer but I have been having the same problem. First, make sure Ninject and Ninject.Web.Common are referenced in the service layer, and that you have a using statement for Ninject.Web.Common in your module class.
I couldn't find InRequestScope in Intellisense. I tried a few times opening and closing the project, and it finally showed up. Didn't do anything but close and re-open Visual Studio and it started working.
I'm new to AutoFac and am currently using custom modules inside my app config to boot up some core F# systems. The code I'm using is
var builder = new ContainerBuilder();
builder.RegisterType<DefaultLogger>().As<IDefaultLogger>();
builder.RegisterModule(new ConfigurationSettingsReader("autofac"));
builder.Build();
And inside my app config I have the appropriate logic to start up the relevant systems. I would like to have access to the DefaultLogger inside my Modules. Metadata for the Module base class has the following options available to me:
protected virtual void AttachToComponentRegistration(IComponentRegistry componentRegistry, IComponentRegistration registration);
protected virtual void AttachToRegistrationSource(IComponentRegistry componentRegistry, IRegistrationSource registrationSource);
public void Configure(IComponentRegistry componentRegistry);
protected virtual void Load(ContainerBuilder builder);
I've only been using Load so far and I can't see any methods on the builder that would allow me to get at the logging service.
When registering something within your modules with autofac instead of using RegisterType method you might use Register method:
builder.Register(c =>
{
IComponentContext ctx = c.Resolve<IComponentContext();
IDefaultLogger logger = ctx.Resolve<IDefaultLogger>();
...do something with logger...
return ...return object you want to register...;
});
The answer turned out to be incredibly simple. I just added IComponentContext as a dependency to my Module's implementation
public class LocalActorSystemModule : Module {
private IComponentContext m_ComponentContext; // A service for resolving dependencies required by this module
public LocalActorSystemModule(IComponentContext componentContext) {
m_ComponentContext = componentContext;
}
And let AutoFac inject the IComponentContext for me. That way I can resolve any dependencies I require inside the module.
Rule of thumb for using every IoC/DI Container: Resolve once! => then you get all dependencies resolved for your requested object. If you try to resolve multiple times, register other objects (in the meantime) you're stuck in hell. Really. If you want to retrieve objects for different purposes at different places and time points (resolved from central registration) you may be looking for the Service Locator Pattern instead (but this is often described as an Anti-Pattern, too).
Modules have the purpose to bundle related registrations (conditionally) as statet in the Autofac documentation:
A module is a small class that can be used to bundle up a set of
related components behind a ‘facade’ to simplify configuration and
deployment.
... so if they are just a sum of registrations and the container has not yet been build you are not able to resolve and use an (even previously registered) component immediately (except calling a method on the registrant itself through OnActivate* hooks or when using instance registration, but I think this is not the case for your example). The components are just in the state of registration but the complete context is not ready for resolving. What would happen if you override the registration in another Module? Then you would have injected different objects... bad idea. Maybe you should rethink your application design and which objects have which responsibilities.
By the way: Logging is a cross cutting concern that is often "injected / resolved" by calling a separate static factory or service instead of doing constructor / property injection (see usage of Common.Logging for example).
public class MyModule : Module
{
private static readonly ILog Log = LogManager.GetLogger<MyModule>();
protected override void Load(ContainerBuilder builder)
{
Log.Debug(msg => msg("Hello")); // log whatever you want here
}
}
You can also try to use AOP libraries and weave the dependency into the Module (using reflection). But I don't think it's worth to try just for logging in a Module.
Anyway: #mr100 has already shown the right usage during registration. There you can also handle activation etc. but not do logging for the Module itself.
I'm using NancyFX and Highway.Data + Entity Framework for an API project. My module has a dependency on a repository, which has a dependency on an DataContext. I need that DataContext to be registered and include the connectionstring from web.config, so I have this:
public class CustomBootstrapper : DefaultNancyBootstrapper
{
protected override void ApplicationStartup(TinyIoC.TinyIoCContainer container, Nancy.Bootstrapper.IPipelines pipelines)
{
//Gotta specify how to register the DataContext to use the connectionstring
container.Register<IDataContext>(
(c, p) =>
new DataContext(ConfigurationManager.ConnectionStrings[1].ConnectionString,
c.Resolve<IMappingConfiguration>()));
base.ApplicationStartup(container, pipelines);
}
}
This sets up the registration so it uses my web.config connectionstring, but also uses whatever IMappingConfiguration was already registered by auto-registration.
But it looks like it's registering it as a singleton instead of per web request. This means that data gets cached between web requests, which is not what I want.
I've tried adding .AsMultiInstance() to the registration above, but then I get an error on startup: "Cannot convert current registration of TinyIoC.TinyIoCContainer+DelegateFactory to multi-instance"
Can anyone suggest how I can register this properly?
Container configurations should be performed in either ConfigureApplicationContainer or ConfigureRequestContainer depending on your life-time requirements.
Hope this helps