Adding Unity to MVC WebApi app - c#

Hello all I've Added Unity to an MVC app. it seems that DI is working with the MVC Portion of the app but i cannot figure out why it wont work with the API part of the application.
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name:"DefaultApi",
routeTemplate:"api/{controller}/{id}",
defaults: new {id = RouteParameter.Optional}
);
config.Formatters.Add(new JsonMediaTypeFormatter());
config.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling =
Newtonsoft.Json.ReferenceLoopHandling.Ignore;
config.Formatters.JsonFormatter.SerializerSettings.Formatting = Newtonsoft.Json.Formatting.None;
}
}
public static class UnityMvcActivator
{
/// <summary>
/// Integrates Unity when the application starts.
/// </summary>
public static void Start(HttpConfiguration configuration)
{
FilterProviders.Providers.Remove(FilterProviders.Providers.OfType<FilterAttributeFilterProvider>().First());
FilterProviders.Providers.Add(new UnityFilterAttributeFilterProvider(UnityConfig.Container));
DependencyResolver.SetResolver(new UnityDependencyResolver(UnityConfig.Container));
// TODO: Uncomment if you want to use PerRequestLifetimeManager
// Microsoft.Web.Infrastructure.DynamicModuleHelper.DynamicModuleUtility.RegisterModule(typeof(UnityPerRequestHttpModule));
}
/// <summary>
/// Disposes the Unity container when the application is shut down.
/// </summary>
public static void Shutdown()
{
UnityConfig.Container.Dispose();
}
}
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Address", action = "Index", id = UrlParameter.Optional }
);
}
}
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
GlobalConfiguration.Configure(WebApiConfig.Register);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
BundleConfig.RegisterBundles(BundleTable.Bundles);
RouteConfig.RegisterRoutes(RouteTable.Routes);
UnityMvcActivator.Start(GlobalConfiguration.Configuration);
}
I am just trying to get a repository to work in the web api but i keep getting
An error occurred when trying to create a controller of type 'AddressSearchController'. Make sure that the controller has a parameterless public constructor.",
this error. I have seen a few posts about this. I have tried them and still cannot get this to work. Does anyone have any suggestions?
public class AddressSearchController:_SimpleController<Address>
{
public AddressSearchController(IRepository<Address> addressRepository) : base(addressRepository)
{
}
[HttpPost]
[Route("api/AddressSearch/Search")]
public IHttpActionResult Search([FromBody] AddressSearchDto addressSearchDto)
{
var addresses = new List<Address>()
{
CreateAddress(1,"Main St", 123),
CreateAddress(2,"Main St", 124),
CreateAddress(3,"Main St", 125),
};
return Ok(addresses);
}
static Address CreateAddress(int id,string street, int houseNumber)
{
return new Address()
{
Id = id,
StreetName = street,
HouseNumber = houseNumber
};
}
}
public static void RegisterTypes(IUnityContainer container)
{
RegisterInstances(container);
}
private static void RegisterInstances(IUnityContainer container)
{
container.RegisterType<IAddressContext, AddressContext>();
container.RegisterType(typeof(IRepository<>), typeof(Repository<>));
}
using System;
using Address_Tracker.Data.Context;
using Address_Tracker.Data.Context.Interfaces;
using Address_Tracker.Data.Repositories;
using Unity;
namespace Address_Tracker
{
/// <summary>
/// Specifies the Unity configuration for the main container.
/// </summary>
public static class UnityConfig
{
#region Unity Container
private static Lazy<IUnityContainer> container =
new Lazy<IUnityContainer>(() =>
{
var container = new UnityContainer();
RegisterTypes(container);
return container;
});
/// <summary>
/// Configured Unity Container.
/// </summary>
public static IUnityContainer Container => container.Value;
#endregion
/// <summary>
/// Registers the type mappings with the Unity container.
/// </summary>
/// <param name="container">The unity container to configure.</param>
/// <remarks>
/// There is no need to register concrete types such as controllers or
/// API controllers (unless you want to change the defaults), as Unity
/// allows resolving a concrete type even if it was not previously
/// registered.
/// </remarks>
public static void RegisterTypes(IUnityContainer container)
{
RegisterInstances(container);
}
private static void RegisterInstances(IUnityContainer container)
{
container.RegisterType<IAddressContext, AddressContext>();
container.RegisterType(typeof(IRepository<>), typeof(Repository<>));
}
}
}

Your AddressSearchController should have a default constructor, or if you have no default / parameterless constructor, then please pass interfaces instead of concrete classes in AddressSearchController.
I believe you may have such a scenario:
public class AddressSearchController : ApiController
{
public AddressSearchController(SomeClassParameter obj)
{
//some code
}
}
What you want actually is ether this:
public class AddressSearchController : ApiController
{
public AddressSearchController() // add default ctor
{
}
public AddressSearchController(SomeClassParameter obj)
{
//some code
}
}
or this:
Register the interface ISomeClassParameter for type SomeClassParameter in Unity
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
UnityConfig.RegisterComponents(); // <----- Add this line
GlobalConfiguration.Configure(WebApiConfig.Register);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
Register component:
container.RegisterType<ISomeClassParameter , SomeClassParameter >();
and do constructor injection :
public class AddressSearchController : ApiController
{
public AddressSearchController(ISomeClassParameter obj)
{
//some code
}
}
Also, make sure you have the WebApi version of Unity
I tried it out, it worked for me:

Related

Web API with Windows Service and MEF

I have created a web api project and run as a windows service.
I have added MEF to load a dll (LibOne.dll) and use it in the controller (ValueController). But unable to get the values in the imported interface.
I followed this link to implement this and added MefDependencyResolver in my web api project.
How to integrate MEF with ASP.NET MVC 4 and ASP.NET Web API
in the values controller the IMyClass is returning always null. How to resolve this?
Is there anything I am mising?
Here is my Web Api Controller
[Export(typeof(ValuesController))]
public class ValuesController : ApiController
{
[Import(typeof(IMyClass))]
private IMyClass Myclass { get; set; }
public String GetString(Int32 id)
{
return Myclass.GetValues();
}
}
SelfHosted Service to run the web api as windows service
protected override void OnStart(string[] args)
{
var config = new HttpSelfHostConfiguration("http://localhost:8080");
Thread.Sleep(10000);
MefConfig.RegisterMef(config);
config.Routes.MapHttpRoute(
name: "API",
routeTemplate: "{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
HttpSelfHostServer server = new HttpSelfHostServer(config);
server.OpenAsync().Wait();
}
MEF registration
public static void RegisterMef(HttpConfiguration config)
{
var assemblyCatalog = new AggregateCatalog();
assemblyCatalog.Catalogs.Add(new DirectoryCatalog(#""));
var container = new CompositionContainer(assemblyCatalog);
var resolver = new MefDependencyResolver(container);
config.DependencyResolver = resolver;
}
Exporting this class from LibOne.dll
[Export(typeof(IMyClass))]
public class Super :IMyClass
{
public string GetValues()
{
return "My value";
}
}
MEFDependencyResolver:
internal class MefDependencyResolver : IDependencyResolver
{
private readonly CompositionContainer _container;
/// <summary />
/// <param name="container"></param>
public MefDependencyResolver(CompositionContainer container)
{
_container = container;
}
/// <summary>
///
/// </summary>
/// <returns></returns>
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;
}
/// <summary>
///
/// </summary>
public void Dispose()
{
}
}

Dependency Injection on Global.asax compilation error

I'm having compilation error when calling my service in global.asax. Im using UnityMvc as my DI. It was working when called in my controllers but no in Global.asax. Here is the error.
Compiler Error Message: CS7036: There is no argument given that corresponds to the required formal parameter 'genreService' of 'MvcApplication.MvcApplication(IGenreService)'
Global.asax.cs
public class MvcApplication : System.Web.HttpApplication
{
private readonly IGenreService _genreService;
public MvcApplication(IGenreService genreService)
{
_genreService = genreService;
}
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
}
GenreService.cs
public partial class GenreService : IGenreService
{
private readonly IRepository<Genre> _genreRepository;
private readonly IRepository<GameGenre> _gameGenreRepository;
public GenreService(IRepository<Genre> genreRepository, IRepository<GameGenre> gameGenreRepository)
{
_genreRepository = genreRepository;
_gameGenreRepository = gameGenreRepository;
}
// methods
}
IGenreService.cs
public partial interface IGenreService
{
// interface
}
UnityConfig.cs
using System;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.Configuration;
using System.Data.Entity;
using Microsoft.AspNet.Identity;
using Microsoft.Owin.Security;
using GameCommerce.Infrastructure.Services.GameLibrary;
using GameCommerce.Infrastructure;
using Microsoft.AspNet.Identity.EntityFramework;
using GameCommerce.Infrastructure.ApplicationUsers;
using System.Web;
using GameCommerce.Infrastructure.Services.Message;
namespace GameCommerce.Web.App_Start
{
/// <summary>
/// Specifies the Unity configuration for the main container.
/// </summary>
public class UnityConfig
{
#region Unity Container
private static Lazy<IUnityContainer> container = new Lazy<IUnityContainer>(() =>
{
var container = new UnityContainer();
RegisterTypes(container);
return container;
});
/// <summary>
/// Gets the configured Unity container.
/// </summary>
public static IUnityContainer GetConfiguredContainer()
{
return container.Value;
}
#endregion
/// <summary>Registers the type mappings with the Unity container.</summary>
/// <param name="container">The unity container to configure.</param>
/// <remarks>There is no need to register concrete types such as controllers or API controllers (unless you want to
/// change the defaults), as Unity allows resolving a concrete type even if it was not previously registered.</remarks>
public static void RegisterTypes(IUnityContainer container)
{
// NOTE: To load from web.config uncomment the line below. Make sure to add a Microsoft.Practices.Unity.Configuration to the using statements.
// container.LoadConfiguration();
// TODO: Register your types here
// container.RegisterType<IProductRepository, ProductRepository>();
container.RegisterType<DbContext, ApplicationDbContext>(new HierarchicalLifetimeManager());
container.RegisterType<UserManager<ApplicationUser>>(new HierarchicalLifetimeManager());
container.RegisterType<IUserStore<ApplicationUser>, UserStore<ApplicationUser>>(new InjectionConstructor(new ApplicationDbContext()));
container.RegisterType<Areas.Admin.Controllers.AccountController>(new InjectionConstructor());
container.RegisterType<Controllers.AccountController>(new InjectionConstructor());
container.RegisterType<IAuthenticationManager>(new InjectionFactory(o => HttpContext.Current.GetOwinContext().Authentication));
container.RegisterType(typeof(IRepository<>), typeof(Repository<>));
container.RegisterType<IGameService, GameService>();
container.RegisterType<IGenreService, GenreService>();
container.RegisterType<IGameDeveloperService, GameDeveloperService>();
container.RegisterType<IGamePublisherService, GamePublisherService>();
container.RegisterType<IMessageService, MessageService>();
}
}
}
Try with the below code:
using Microsoft.Practices.Unity;
public class MvcApplication : System.Web.HttpApplication
{
private readonly IGenreService _genreService;
public MvcApplication()
{
_genreService = GameCommerce.Web.App_Start.UnityConfig.GetConfiguredContainer().Resolve<IGenreService>();
}
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
}
DepedencyResolver in MVC by default is used for resolution in controllers, so here we are using explicity using the Container for resolution in 'MvcApplication'.

OData no http resource was found that matches the request uri

I'm having some trouble getting my Odata service working with my MVC 4 site.
Can you help me figure out what I'm doing wrong?
Here is my WebApiConfig:
public static class WebApiConfig
{
/// <summary>
/// The Register method
/// </summary>
/// <param name="config">The config.</param>
public static void Register(HttpConfiguration config)
{
config.MapODataServiceRoute("odata", "odata", GetEdmModel(), new DefaultODataBatchHandler(GlobalConfiguration.DefaultServer));
config.EnsureInitialized();
}
private static IEdmModel GetEdmModel()
{
ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
builder.Namespace = "ThisClassesNamespace";
builder.ContainerName = "DefaultContainer";
builder.EntitySet<QueryRequest>("QueryRequests");
var edmModel = builder.GetEdmModel();
return edmModel;
}
}
here is the global.asax's application_start method:
protected void Application_Start()
{
Application["Name"] = "Administration Web Console";
GlobalConfiguration.Configure(WebApiConfig.Register);
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
Error += MvcApplication_Error;
var maplayerDao = new MapLayerDao();
maplayerDao.UpdateProvisioningData();
var factory = new CustomControllerFactory();
ControllerBuilder.Current.SetControllerFactory(factory);
}
finally, here is what the controler's get method looks like
public class QueryRequestsController : ODataController
{
private static ODataValidationSettings _validationSettings = new ODataValidationSettings();
private QueryRequestDao dao = new QueryRequestDao();
// GET: odata/QueryRequests
[HttpGet]
public IHttpActionResult GetQueryRequests()
{
// validate the query.
try
{
// queryOptions.Validate(_validationSettings);
}
catch (ODataException ex)
{
return BadRequest(ex.Message);
}
return Ok<IEnumerable<QueryRequest>>(dao.GetQueryRequests());
}
I can get the metadata just fine at http://10.78.14.177:8040/odata/
which gives me:
{
"#odata.context":"http://10.78.14.177:8040/odata/$metadata","value":[
{
"name":"QueryRequests","kind":"EntitySet","url":"QueryRequests"
}
]
}
but when I go to http://10.78.14.177:8040/odata/QueryRequests
I get No HTTP resource was found that matches the request URI 'http://10.78.14.177:8040/odata/QueryRequests'.
I think the MVC routing is getting this request and it is not going to the OData service... but I'm not sure what the fix is.
Any ideas?

Extend windsor dependency injection to cover web api part of website?

I have an ASP.NET MVC application, which uses Windsor for dependency injection.
Now, I have started to build an API inside the application under /controllers/api .
In my first API controller, I need access to some services from my domain project, which is added by Windsor. This works perfectly for normal controllers. However, whwen I for instance access /api/officeproduct/gettest , I get the following error:
This XML file does not appear to have any style information associated with it. The document tree is shown below.
<Error>
<script id="tinyhippos-injected"/>
<Message>An error has occurred.</Message>
<ExceptionMessage>
Type 'LetterAmazer.Websites.Client.Controllers.Api.OfficeProductController' does not have a default constructor
</ExceptionMessage>
<ExceptionType>System.ArgumentException</ExceptionType>
<StackTrace>
at System.Linq.Expressions.Expression.New(Type type) at System.Web.Http.Internal.TypeActivator.Create[TBase](Type instanceType) at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.GetInstanceOrActivator(HttpRequestMessage request, Type controllerType, Func`1& activator) at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)
</StackTrace>
</Error>
I really don't know how to fix it, despite using a lot of time so way. Any ideas how to get it to work?
My API controller:
public class OfficeProductController : ApiController
{
private IOfficeProductService officeProductService;
public OfficeProductController(IOfficeProductService officeProductService)
{
this.officeProductService = officeProductService;
}
[System.Web.Http.HttpPost]
public ActionResult Create(OfficeProductViewModel model)
{
var officeProduct = new OfficeProduct()
{
CountryId = 1,
ProductScope = ProductScope.Single,
LetterDetails = new LetterDetails()
{
LetterColor = LetterColor.BlackWhite,
LetterPaperWeight = LetterPaperWeight.Eight,
LetterProcessing = LetterProcessing.Dull,
LetterSize = LetterSize.A4,
LetterType = LetterType.Pres
},
OfficeId = 1
};
officeProductService.Create(officeProduct);
return new JsonResult();
}
[System.Web.Http.HttpPost]
public ActionResult Test(string id)
{
return new ContentResult() { Content = id };
}
[System.Web.Http.HttpGet]
public ActionResult Gettest()
{
return new ContentResult() {Content ="hej"};
}
}
Web API registration:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
Global.asax:
public class MvcApplication : System.Web.HttpApplication, IContainerAccessor
{
protected void Application_Start()
{
log4net.Config.XmlConfigurator.Configure();
InitializeContainer();
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
private void InitializeContainer()
{
var oldProvider = FilterProviders.Providers.Single(f => f is FilterAttributeFilterProvider);
FilterProviders.Providers.Remove(oldProvider);
Container.Register(Component.For<IWindsorContainer>().Instance(this.Container));
Container.Install(new BootstrapInstaller());
registerCustom();
Container.Install(new WebWindsorInstaller());
var provider = new WindsorFilterAttributeFilterProvider(this.Container);
FilterProviders.Providers.Add(provider);
DependencyResolver.SetResolver(new WindsorDependencyResolver(ServiceFactory.Container));
}
private void registerCustom()
{
// All services in service DLL
var assembly = Assembly.LoadFrom(Server.MapPath("~/bin/LetterAmazer.Business.Services.dll"));
;
Container.Register(
Classes.FromAssembly(assembly)
.InNamespace("LetterAmazer.Business.Services.Services")
.WithServiceAllInterfaces());
Container.Register(
Classes.FromAssembly(assembly)
.InNamespace("LetterAmazer.Business.Services.Services.FulfillmentJobs")
.WithServiceAllInterfaces());
Container.Register(
Classes.FromAssembly(assembly)
.InNamespace("LetterAmazer.Business.Services.Services.PaymentMethods.Implementations")
.WithServiceAllInterfaces());
// All factories in service DLL
Container.Register(
Classes.FromAssembly(assembly)
.InNamespace("LetterAmazer.Business.Services.Factory")
.WithServiceAllInterfaces());
Container.Register(Component.For<LetterAmazerEntities>());
}
public IWindsorContainer Container
{
get { return ServiceFactory.Container; }
}
}
Windsor - dependency resolver:
/// <summary>
/// Reference: http://stackoverflow.com/questions/4140860/castle-windsor-dependency-resolver-for-mvc-3
/// </summary>
public class WindsorDependencyResolver : IDependencyResolver
{
private readonly IWindsorContainer container = null;
/// <summary>
///
/// </summary>
/// <param name="container"></param>
public WindsorDependencyResolver(IWindsorContainer container)
{
this.container = container;
}
/// <summary>
///
/// </summary>
/// <param name="serviceType"></param>
/// <returns></returns>
public object GetService(Type serviceType)
{
return container.Kernel.HasComponent(serviceType) ? container.Resolve(serviceType) : null;
}
/// <summary>
///
/// </summary>
/// <param name="serviceType"></param>
/// <returns></returns>
public IEnumerable<object> GetServices(Type serviceType)
{
return container.Kernel.HasComponent(serviceType) ? container.ResolveAll(serviceType).Cast<object>() : new object[] {};
}
}
Windsor - controller factory
/// <summary>
/// Controller Factory class for instantiating controllers using the Windsor IoC container.
/// </summary>
public class WindsorControllerFactory : DefaultControllerFactory
{
private static readonly ILog logger = LogManager.GetLogger(typeof(WindsorControllerFactory));
private readonly IWindsorContainer container = null;
/// <summary>
///
/// </summary>
/// <param name="container"></param>
public WindsorControllerFactory(IWindsorContainer container)
{
if (container == null)
{
throw new ArgumentNullException("container");
}
this.container = container;
}
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
if (controllerType == null)
{
throw new HttpException(404,
string.Format("The controller for path '{0}' could not be found or it does not implement IController.",
requestContext.HttpContext.Request.Path));
}
IController controller = (IController)container.Resolve(controllerType);
return controller;
}
/// <summary>
///
/// </summary>
/// <param name="controller"></param>
public override void ReleaseController(IController controller)
{
var disposable = controller as IDisposable;
if (disposable != null)
{
disposable.Dispose();
}
container.Release(controller);
}
You need to create a class that implements IHttpControllerActivator then register it when you initialize the container.
WindsorHttpControllerActivator
public class WindsorHttpControllerActivator : IHttpControllerActivator
{
private readonly IWindsorContainer _container;
public WindsorHttpControllerActivator(IWindsorContainer container)
{
_container = container;
}
public IHttpController Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)
{
var controller = (IHttpController)_container.Resolve(controllerType);
request.RegisterForDispose(new Release(() => _container.Release(controller)));
return controller;
}
private class Release : IDisposable
{
private readonly Action _release;
public Release(Action release)
{
_release = release;
}
public void Dispose()
{
_release();
}
}
}
Register HttpControllerActivator
private void InitializeContainer()
{
var oldProvider = FilterProviders.Providers.Single(f => f is FilterAttributeFilterProvider);
FilterProviders.Providers.Remove(oldProvider);
Container.Register(Component.For<IWindsorContainer>().Instance(this.Container));
Container.Install(new BootstrapInstaller());
registerCustom();
Container.Install(new WebWindsorInstaller());
var provider = new WindsorFilterAttributeFilterProvider(this.Container);
FilterProviders.Providers.Add(provider);
DependencyResolver.SetResolver(new WindsorDependencyResolver(ServiceFactory.Container));
// register WebApi controllers
GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpControllerActivator), new WindsorHttpControllerActivator(ServiceFactory.Container));
}

How to use Ninject with WebApi?

I need to use Ninject on a Web APi app (I created it using the empty web api template).
I installed the following nuget package :
Ninject.Web.WebApi
Ninject.MVC3
Here is my application_start
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
My Ninject.Web.Common
[assembly: WebActivator.PreApplicationStartMethod(typeof(rb.rpg.backend.App_Start.NinjectWebCommon), "Start")]
[assembly: WebActivator.ApplicationShutdownMethodAttribute(typeof(rb.rpg.backend.App_Start.NinjectWebCommon), "Stop")]
namespace rb.rpg.backend.App_Start
{
using System;
using System.Web;
using Microsoft.Web.Infrastructure.DynamicModuleHelper;
using Ninject;
using Ninject.Web.Common;
using Raven.Client;
using RemiDDD.Framework.Cqrs;
using System.Web.Http.Dependencies;
using System.Web.Http;
using System.Collections.Generic;
using Ninject.Web.WebApi;
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);
//System.Web.Mvc.DependencyResolver.SetResolver(new LocalNinjectDependencyResolver(kernel));
GlobalConfiguration.Configuration.DependencyResolver = new NinjectDependencyResolver(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<IDocumentSession>()
.ToMethod(ctx => WebApiApplication.DocumentStore.OpenSession())
.InRequestScope();
kernel.Bind<MessageProcessor>()
.ToMethod(ctx =>
{
var MessageProcessor = new MessageProcessor(kernel);
/*...*/
return MessageProcessor;
})
.InSingletonScope();
}
}
}
When I rebuild the app the first loading is fine, my contrller gets my IDocumentSession. But when I reload the same page, I got the errror
"the type .. has no default constructor"
Here is how I set it up in my Web API projects:
Download regular Ninject from nuget.org
PM> Install-Package Ninject
In your Web API project add new folder named Infrastructure in that folder create 2 files:
NInjectDependencyScope.cs with content:
public class NInjectDependencyScope : IDependencyScope
{
private IResolutionRoot _resolutionRoot;
public NInjectDependencyScope(IResolutionRoot resolutionRoot)
{
_resolutionRoot = resolutionRoot;
}
public void Dispose()
{
var disposable = _resolutionRoot as IDisposable;
if (disposable != null)
disposable.Dispose();
_resolutionRoot = null;
}
public object GetService(Type serviceType)
{
return GetServices(serviceType).FirstOrDefault();
}
public IEnumerable<object> GetServices(Type serviceType)
{
var request = _resolutionRoot.CreateRequest(serviceType, null, new IParameter[0], true, true);
return _resolutionRoot.Resolve(request);
}
}
and NInjectDependencyResolver.cs with content:
public class NInjectDependencyResolver : NInjectDependencyScope, IDependencyResolver
{
private IKernel _kernel;
public NInjectDependencyResolver(IKernel kernel) : base(kernel)
{
_kernel = kernel;
}
public IDependencyScope BeginScope()
{
return new NInjectDependencyScope(_kernel.BeginBlock());
}
}
In Global.asax file in Application_Start() method add:
//Ninject dependency injection configuration
var kernel = new StandardKernel();
kernel.Bind<IXyzRepository>().To<EFXyzRepository>();
GlobalConfiguration.Configuration.DependencyResolver = new NInjectDependencyResolver(kernel);
so that your final Global.asax file will look like this:
public class XyzApiApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
GlobalConfiguration.Configure(WebApiConfig.Register);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
//Ninject dependency injection configuration
var kernel = new StandardKernel();
//Your dependency bindings
kernel.Bind<IXyzRepository>().To<EFXyzRepository>();
GlobalConfiguration.Configuration.DependencyResolver = new NInjectDependencyResolver(kernel);
}
}
An that is it!
Here is the example of usage:
public class PersonController : ApiController
{
private readonly IXyzRepository repository;
public PersonController(IXyzRepository repo)
{
repository = repo;
}
...
...
...
I hope this helps.

Categories

Resources