How Do I convert the following Ninject DI to Unity? I'm having trouble understanding the correct syntax.
/// <summary>
/// Load your modules or register your services here!
/// </summary>
/// <param name="kernel">The kernel.</param>
private static void RegisterServices(IKernel kernel)
{
Database.SetInitializer(new MigrateDatabaseToLatestVersion<DefaultMembershipRebootDatabase, BrockAllen.MembershipReboot.Ef.Migrations.Configuration>());
var config = MembershipRebootConfig.Create();
kernel.Bind<MembershipRebootConfiguration>().ToConstant(config);
kernel.Bind<UserAccountService>().ToSelf();
kernel.Bind<AuthenticationService>().To<SamAuthenticationService>();
kernel.Bind<IUserAccountQuery>().To<DefaultUserAccountRepository>().InRequestScope();
kernel.Bind<IUserAccountRepository>().To<DefaultUserAccountRepository>().InRequestScope();
}
Registering a single instance is done using the RegisterInstance method.
Registering types as 'self' is done using the RegisterType<T>() method.
Registering types with a request lifestyle is done using the HierarchicalLifetimeManager.
Related
I started creating a PoC following SO this post but I wasn't able to get a very basic sample to work.
What I did:
I created an ASP.NET MVC project using empty template and MVC references.
I added Bootstrapper, CustomControllerFactory and CustomViewEngine classes and also the corresponding lines in Application_Start.
I created an ASP.NET MVC project using MVC template.
I added the Export and PartCreationPolicy decorators on HomeController.
I published the module project to a folder inside /Modules directory -in WebHost root path.
What didn't work:
The method CompositionContainer.GetExportedValue throws an exception saying that it couldn't load one or more required types and that there is more information on LoaderExceptions property. That property is an array with 77 instances of what appears to be the same exception:
Could not load file or assembly Antlr3.Runtime, Version=3.4.1.9004, Culture=neutral, PublicKeyToken=eb42632606e9261f or one of its dependencies.
In FusionLog property I can see that the problem is related to the assembly version (see here).
I found a workaround for "solving" this by copying the dependentAssembly declarations from the module's web.config to the WebHost configuration file. However I'd like to avoid this as the WebHost should not be modified based on the module's needs.
Even after the workaround, it didn't work. While rendering the view, it threw this exception:
CS0234: The type or namespace name 'Optimization' does not exist in the namespace 'System.Web' (are you missing an assembly reference?)
For your help is share a full test project using MEF. visit this github link.
You need something like--
public class AzRDependencyResolver : System.Web.Http.Dependencies.IDependencyResolver, System.Web.Mvc.IDependencyResolver
{
private readonly CompositionContainer _container;
public AzRDependencyResolver(CompositionContainer container)
{
_container = container;
}
public IDependencyScope BeginScope()
{
return this;
}
/// <summary>
/// Called to request a service implementation.
///
/// Here we call upon MEF to instantiate implementations of dependencies.
/// </summary>
/// <param name="serviceType">Type of service requested.</param>
/// <returns>Service implementation or null.</returns>
public object GetService(Type serviceType)
{
if (serviceType == null)
throw new ArgumentNullException("serviceType");
var name = AttributedModelServices.GetContractName(serviceType);
var export = _container.GetExportedValueOrDefault<object>(name);
return export;
}
/// <summary>
/// Called to request service implementations.
///
/// Here we call upon MEF to instantiate implementations of dependencies.
/// </summary>
/// <param name="serviceType">Type of service requested.</param>
/// <returns>Service implementations.</returns>
public IEnumerable<object> GetServices(Type serviceType)
{
if (serviceType == null)
throw new ArgumentNullException("serviceType");
var exports = _container.GetExportedValues<object>(AttributedModelServices.GetContractName(serviceType));
return exports;
}
public void Dispose()
{
}
}
I want to preserve the DI abstraction layer Kephas provides, but in my particular case I need to register a service which is imported from a third-party library. Given this, I cannot annotate the service with the [AppServiceContract] attribute required for service registration. Is there a way to achieve this?
Yes there is. Here are the steps to follow:
Define a class implementing IConventionsRegistrar.
Use the conventions builder to register the desired services.
Sample code:
public class MyConventionsRegistrar : IConventionsRegistrar
{
/// <summary>
/// Registers the conventions.
/// </summary>
/// <param name="builder">The registration builder.</param>
/// <param name="candidateTypes">The candidate types which can take part in the composition.</param>
/// <param name="registrationContext">Context for the registration.</param>
public void RegisterConventions(
IConventionsBuilder builder,
IEnumerable<TypeInfo> candidateTypes,
ICompositionRegistrationContext registrationContext)
{
//... here you can use the conventions builder to register your services using the fluent API. The candidate types are provided if you need the identified application types. A couple of examples are provided below:
// shared/singleton service exported as IMyService with MyService implementation.
builder.ForType(typeof(MyServiceImpl))
.Export(b => b.AsContractType(typeof(IMyService)))
.Shared();
// instance-based multiple services exported as IMultiImplService
builder.ForTypesDerivedFrom(typeof(IMultiImplService))
.Export(b => b.AsContractType(typeof(IMultiImplService)));
}
There is a second way of registering services, however by the means of service descriptors instead of a fluent API. For this case, follow the steps:
Define a class implementing IAppServiceInfoProvider.
Return the descriptors of the desired services.
Sample code with the same registrations as above:
public class MyAppServiceInfoProvider : IAppServiceInfoProvider
{
/// <summary>
/// Gets an enumeration of application service information objects.
/// </summary>
/// <param name="candidateTypes">The candidate types which can take part in the composition.</param>
/// <param name="registrationContext">Context for the registration.</param>
/// <returns>
/// An enumeration of application service information objects and their associated contract type.
/// </returns>
public IEnumerable<(TypeInfo contractType, IAppServiceInfo appServiceInfo)> GetAppServiceInfos(IEnumerable<TypeInfo> candidateTypes, ICompositionRegistrationContext registrationContext)
{
yield return (typeof(IMyService).GetTypeInfo(),
new AppServiceInfo(typeof(IMyService),
typeof(MyServiceImpl),
AppServiceLifetime.Shared));
yield return (typeof(IMultiImplService).GetTypeInfo(),
new AppServiceInfo(typeof(IMultiImplService),
AppServiceLifetime.Instance,
allowMultiple: true));
}
Both cases are autodiscovered and, at the proper time, the registration methods are called. However, in the second case, the advantage is that the registrations are available as service metadata for querying at a later time.
In the startup.cs, I want to define an extended ServiceProvider: It basically wraps the default IServiceProvider implementation.
public IServiceProvider ConfigureServices(IServiceCollection services)
{
[...]
var servicesProvider = services.BuildExtendedServiceProvider();
return servicesProvider;
}
Here is the core extended service provider implementation
/// <summary>
/// Extends the native asp.net service provider
/// </summary>
public class ExtendedServicesProvider : IServiceProvider
{
private readonly IServiceProvider _serviceProvider;
/// <summary>
/// Creates a new instance of <see cref="ExtendedServicesProvider"/> provider based on the native mvc <see cref="IServiceProvider"/>
/// </summary>
/// <param name="serviceProvider"></param>
public ExtendedServicesProvider(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
/// <inheritDoc />
public object GetService(Type serviceType)
{
var resolvedService = _serviceProvider.GetService(serviceType);
[...]
return resolvedService;
}
}
At startup, I can see that GetService is called for each service with "singleton" life time (great!!)
However, it is not called anymore after that, and the default ServiceProvider is called instead...
By the way, if I request the resolution of IServiceProvider, this is the native one that I get.
I would like my serviceProvider to replace completely the native one and to be called EVERY TIME.
Did I miss something??
Ok, I just checked the source code (I should have checked before posting the question sorry).
https://github.com/aspnet/DependencyInjection/blob/master/src/Microsoft.Extensions.DependencyInjection/ServiceProvider.cs
The build method adds by itself the IServiceProvider type with the native instance.
As there seem to have no way to modify it properly (without reflection on "_table" field I mean :-). It seems to me that the approach is clearly not good.
I think I'll try other dependency injection engines such as Autofac, but I really wanted to keep the native engine that seemed to me really light weight.
I'm currently working on a project whereby I will be developing views that will be pre-compiled and will be part of an external MVC 3.0 web solution I do not have any control over.
Part of my requirements is that I will need to access an underlying database in order to get some data. I would like to use Ninject (I've been informed that's what the external solution uses) to inject the database instance into my controllers as necessary.
I understand that you add the bindings in such a place as the Global.asax however I do not have access to this as that is part of the external solution out of my control.
Is there anyway I can create this dependency injection in my project that contains the pre-compiled views etc and ensure it is resolved when the external project loads our controller?
If this is too vague let me know and I'll try and offer more information.
EDIT:
Initially upon taken on Darin's suggestion I got the exception below:
System.InvalidOperationException crossed a native/managed boundary
Message=Sequence contains no elements
Source=System.Core
StackTrace:
at System.Linq.Enumerable.Single[TSource](IEnumerable`1 source)
at Ninject.Web.Mvc.NinjectMvcHttpApplicationPlugin.Start() in c:\Projects\Ninject\ninject.web.mvc\mvc3\src\Ninject.Web.Mvc\NinjectMvcHttpApplicationPlugin.cs:line 53
at Ninject.Web.Common.Bootstrapper.<Initialize>b__0(INinjectHttpApplicationPlugin c) in c:\Projects\Ninject\Ninject.Web.Common\src\Ninject.Web.Common\Bootstrapper.cs:line 52
at Ninject.Infrastructure.Language.ExtensionsForIEnumerableOfT.Map[T](IEnumerable`1 series, Action`1 action) in c:\Projects\Ninject\ninject\src\Ninject\Infrastructure\Language\ExtensionsForIEnumerableOfT.cs:line 32
at Ninject.Web.Common.Bootstrapper.Initialize(Func`1 createKernelCallback) in c:\Projects\Ninject\Ninject.Web.Common\src\Ninject.Web.Common\Bootstrapper.cs:line 52
at MyApp.App_Start.NinjectWebCommon.Start() in C:\App\NinjectWebCommon.cs:line 28
InnerException:
However upon thinking about it, the bootstrapper should already be initialised in our external MVC application (assuming they are using this method I guess). So I don't need to do all the initialisation all I need to do is register my dependencies with the current Kernal.
Something like:
public static class NinjectWebCommon
{
private static readonly Bootstrapper bootstrapper = new Bootstrapper();
/// <summary>
/// Starts the application
/// </summary>
public static void Start()
{
RegisterServices(bootstrapper.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<IDataContext>().To<ApiDataContext>();
}
}
When doing this I now get the items injected. However I'm not 100% this is the correct solution but it seems to work?
I understand that you add the bindings in such a place as the Global.asax
Not necessarily. Have you recently installed the Ninject.MVC3 NuGet in a new MVC application? If you haven't I invite you to do so now. Simply create a new ASP.NET MVC 3 project using the Internet Application template in Visual Studio and install this NuGet. Ready?
After doing that you will notice that the NuGet package created in App_Start folder to your project. It didn't touch at any Global.asax. Now let's inspect the contents of the NinjectWebCommon.cs file added to this folder:
[assembly: WebActivator.PreApplicationStartMethod(typeof(MvcApplication1.App_Start.NinjectWebCommon), "Start")]
[assembly: WebActivator.ApplicationShutdownMethodAttribute(typeof(MvcApplication1.App_Start.NinjectWebCommon), "Stop")]
namespace MvcApplication1.App_Start
{
using System;
using System.Web;
using Microsoft.Web.Infrastructure.DynamicModuleHelper;
using Ninject;
using Ninject.Web.Common;
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)
{
}
}
}
Notice the WebActivator's PreApplicationStartMethod and ApplicationShutdownMethodAttribute assembly attributes that allow you to plug code that executes when an ASP.NET application respectively starts and shuts down.
Alright, now simply put this code in your library and configure your kernel in the RegisterServices method.
Hi
I want to use Autofac in my asp.net mvc appliation and here is the code I have in global.asxc file :
protected void Application_Start()
{
....
var builder = new ContainerBuilder();
builder.RegisterControllers(Assembly.GetExecutingAssembly());
IContainer container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
}
but when I run the project, I see this error :
This module requires that the HttpApplication (Global Application Class) implements IContainerProviderAccessor
what is wrong ?
I had the same problem as the OP, but my solution was different.
From here:
Remove Old Items
Remove IContainerProviderAccessor interface from Global.asax. This implementation is no longer used by ASP.NET MVC integration.
Remove references to the AutofacControllerFactory. The new MVC integration uses the MVC DependencyResolver class for integration instead.
Remove ASP.NET Autofac HTTP module configurations. Previously there were some Autofac ContainerDisposal and PropertyInjection modules required in your web.config. These should be removed.
A minimal global.asax.cs setup for autofac for asp.net mvc3 could look like this:
(RegisterRoutes is removed from the code). As opposed to previous versions of asp.net mvc (from http://code.google.com/p/autofac/wiki/Mvc3Integration)
the HttpApplication class no longer needs to implement the IContainerProviderAccessor interface as described in the ASP.NET Integration documentation. All code related to implementing the interface should be removed your Global.asax.cs file.
You will also need a reference to Autofac.Integration.Mvc.dll
using System;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using Autofac;
using Autofac.Integration.Mvc;
namespace ApplicationX
{
public class MvcApplication : HttpApplication
{
private static IContainer _container;
/// <summary>
/// Gets the container.
/// </summary>
public IContainer Container
{
get { return _container; }
}
// RegisterRoutes and RegisterGlobalFilters removed ...
/// <summary>
/// Fired when the first resource is requested from the web server and the web application starts
/// </summary>
protected void Application_Start()
{
// Register: create and configure the container
_container = BootstrapContainer();
DependencyResolver.SetResolver(new AutofacDependencyResolver(_container));
// MVC Stuff
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
}
/// <summary>
/// Fired when the web application ends
/// </summary>
public void Application_End()
{
// Release: remember to dispose of your container when your application is about to shutdown to let it gracefully release all components and clean up after them
_container.Dispose();
}
/// <summary>
/// Bootstrapper is the place where you create and configure your container
/// </summary>
/// <returns>An Autofac container</returns>
private IContainer BootstrapContainer()
{
var builder = new ContainerBuilder();
// You can make property injection available to your MVC views by adding the ViewRegistrationSource to your ContainerBuilder before building the application container.
builder.RegisterSource(new ViewRegistrationSource());
// An example of a module that registers the dependencies for a ServiceLayer of your application
builder.RegisterModule(new ServiceModule());
builder.RegisterControllers(typeof(MvcApplication).Assembly);
return builder.Build();
}
}
}