I am wiring up Ninject with MVC4 and have it working to the point it's trying to actually resolve dependencies. However, I am getting the following exception:
Method not found: 'System.Web.Http.Services.DependencyResolver System.Web.Http.HttpConfiguration.get_ServiceResolver()'.
Anyone ran into this and have a work around?
GlobalConfiguration.Configuration.ServiceResolver was replaced with GlobalConfiguration.Configuration.DependencyResolver in the RC. So I guess the Ninject package you are using is simply not designed for the RC. It was one of the breaking changes.
So here are the steps to make Ninject work with ASP.NET MVC 4 Web API RC:
Create a new ASP.NET MVC 4 application using the Empty template
Declare an interface:
public interface IFoo
{
string GetBar();
}
Then an implementation:
public class Foo : IFoo
{
public string GetBar()
{
return "the bar";
}
}
Then add an API controller:
public class ValuesController : ApiController
{
private readonly IFoo _foo;
public ValuesController(IFoo foo)
{
_foo = foo;
}
public string Get()
{
return _foo.GetBar();
}
}
Install the Ninject.Mvc3 NuGet package (Install-Package Ninject.Mvc3)
Define a custom API dependency resolver as shown in this gist:
public class NinjectDependencyScope : IDependencyScope
{
private IResolutionRoot resolver;
internal NinjectDependencyScope(IResolutionRoot resolver)
{
Contract.Assert(resolver != null);
this.resolver = resolver;
}
public void Dispose()
{
IDisposable disposable = resolver as IDisposable;
if (disposable != null)
disposable.Dispose();
resolver = null;
}
public object GetService(Type serviceType)
{
if (resolver == null)
throw new ObjectDisposedException("this", "This scope has already been disposed");
return resolver.TryGet(serviceType);
}
public IEnumerable<object> GetServices(Type serviceType)
{
if (resolver == null)
throw new ObjectDisposedException("this", "This scope has already been disposed");
return resolver.GetAll(serviceType);
}
}
public class NinjectDependencyResolver : NinjectDependencyScope, IDependencyResolver
{
private IKernel kernel;
public NinjectDependencyResolver(IKernel kernel)
: base(kernel)
{
this.kernel = kernel;
}
public IDependencyScope BeginScope()
{
return new NinjectDependencyScope(kernel.BeginBlock());
}
}
In your ~/App_Start/NinjectWebCommon.cs/CreateKernel method that was created when you installed the NuGet add the following line after the RegisterServices(kernel); line:
GlobalConfiguration.Configuration.DependencyResolver = new NinjectDependencyResolver(kernel);
Configure your kernel:
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<IFoo>().To<Foo>();
}
Hit F5 and navigate to /api/values
You are presented with the bar.
Obviously when the RC hits RTM I hope there will be a Ninject.Mvc4 NuGet that will shorten those 10 steps to maximum 5.
Related
I trying create generic repository for ms sql db. Earlier i worked with something like this but with mongo db. I can compile project. but when i trying sent request i see error: "An error occurred when trying to create a controller of type 'EmployeeController'. Make sure that the controller has a parameterless public constructor." can anybody help me?
namespace TestTask.Util
{public class NinjectDependencyResolver
{
private IKernel kernel;
public NinjectDependencyResolver(IKernel kernelParam)
{
kernel = kernelParam;
AddBindings();
}
public object GetService(Type serviceType)
{
return kernel.TryGet(serviceType);
}
public IEnumerable<object> GetServices(Type serviceType)
{
return kernel.GetAll(serviceType);
}
private void AddBindings()
{
// repository
kernel.Bind<IEmployeeRepository>().To<EmployeeRepository>();
}
}
controller
namespace TestTask.Controllers
{
[RoutePrefix("api/v1")]
public class EmployeeController : ApiController
{
private readonly IEmployeeRepository _employeeRepository;
public EmployeeController(IEmployeeRepository employeeRepository) : base()
{
_employeeRepository = employeeRepository;
}
[HttpGet]
[Route("getItems")]
public IHttpActionResult GetItems(int take = 8, int skip = 0)
{
if(take<1|| skip < 0)
{
ModelState.AddModelError("Error", "Invalid take or skip params.");
return BadRequest(ModelState);
}
var result = _employeeRepository.Find(x => x.Id >= 0, x=>x.Id, take, skip);
return Ok(result);
}
[HttpGet]
[Route("pageCount")]
public IHttpActionResult PageCount(int itemsInPage)
{
var TotalCount = _employeeRepository.Count(x => x.Id >= 0);
var result = Math.Ceiling((double)TotalCount / (double)itemsInPage);
return Ok(result);
}
}
}
generic repository
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;
using System.Web;
namespace TestTask.Context
{
public abstract class GenericRepository<TEntity> : IRepository<TEntity> where TEntity : class
{
private DefaultConnection context = new DefaultConnection();
public virtual List<TEntity> Find(Expression<Func<TEntity, bool>> predicate, Expression<Func<TEntity, object>> order, int take =50, int skip=0) //where TEntity : class
{
return context.Set<TEntity>().Where(predicate).OrderBy(order).Skip(skip).Take(take).ToList();
}
public virtual int Count(Expression<Func<TEntity, bool>> predicate)
{
return context.Set<TEntity>().Where(predicate).Count();
}
}
}
I had to do this a while back and remember it not being as straight forward with Web API as it is with MVC.
I posted details and a demo project as part of a unit of work example here, and github project here.
Below are the pieces for configuring dependency injection with Ninject.
UnitOfWorkExample.WebApi/Controllers/ProductsController.cs
namespace UnitOfWorkExample.WebApi.Controllers
{
[RoutePrefix("products")]
public class ProductsController : ApiController
{
private IProductService _productService;
public ProductsController(IProductService productService)
{
_productService = productService;
}
[Route]
public IHttpActionResult GetProducts()
{
// ensure there are products for the example
if (!_productService.GetAll().Any())
{
_productService.Create(new Product { Name = "Product 1" });
_productService.Create(new Product { Name = "Product 2" });
_productService.Create(new Product { Name = "Product 3" });
}
return Ok(_productService.GetAll());
}
}
}
UnitOfWorkExample.WebApi/App_Start/NinjectWebCommon.cs
namespace UnitOfWorkExample.WebApi.App_Start
{
using System;
using System.Web;
using Microsoft.Web.Infrastructure.DynamicModuleHelper;
using Ninject;
using Ninject.Web.Common;
using Ninject.Extensions.Conventions;
using System.Web.Http;
using UnitOfWorkExample.Domain.Helpers;
using UnitOfWorkExample.Data.Helpers;
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);
// Install our Ninject-based IDependencyResolver into the Web API config
GlobalConfiguration.Configuration.DependencyResolver = new NinjectResolver(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)
{
// unit of work per request
kernel.Bind<IUnitOfWork>().To<UnitOfWork>().InRequestScope();
// default binding for everything except unit of work
kernel.Bind(x => x.FromAssembliesMatching("*").SelectAllClasses().Excluding<UnitOfWork>().BindDefaultInterface());
}
}
}
UnitOfWorkExample.WebApi/App_Start/NinjectDependencyResolver.cs
namespace UnitOfWorkExample.WebApi.App_Start
{
public class NinjectScope : IDependencyScope
{
protected IResolutionRoot resolutionRoot;
public NinjectScope(IResolutionRoot kernel)
{
resolutionRoot = kernel;
}
public object GetService(Type serviceType)
{
IRequest request = resolutionRoot.CreateRequest(serviceType, null, new Parameter[0], true, true);
return resolutionRoot.Resolve(request).SingleOrDefault();
}
public IEnumerable<object> GetServices(Type serviceType)
{
IRequest request = resolutionRoot.CreateRequest(serviceType, null, new Parameter[0], true, true);
return resolutionRoot.Resolve(request).ToList();
}
public void Dispose()
{
IDisposable disposable = (IDisposable)resolutionRoot;
if (disposable != null) disposable.Dispose();
resolutionRoot = null;
}
}
public class NinjectResolver : NinjectScope, IDependencyResolver
{
private IKernel _kernel;
public NinjectResolver(IKernel kernel)
: base(kernel)
{
_kernel = kernel;
}
public IDependencyScope BeginScope()
{
return new NinjectScope(_kernel.BeginBlock());
}
}
}
ASP.NET does not inject anything into controllers by default. Instead, it looks for a matching controller and just uses new. So it needs a controller that has a default constructor with no parameters-- unless you do something special to add DI.
To add dependency injection to your controllers, you need to register a custom controller factory. The factory should use Ninject to instantiate the controller, which will automatically populate its constructor arguments with the appropriate dependencies. Here is a bare bones example (you will need to modify it to allow other controller types, as well as implement the rest of the interface):
public class CustomControllerFactory : IControllerFactory
{
public IController CreateController(System.Web.Routing.RequestContext requestContext, string controllerName)
{
return _kernel.Get<EmployeeController>();
}
}
You can register it in startup with code like this:
protected void Application_Start()
{
IControllerFactory factory = new CustomControllerFactory();
ControllerBuilder.Current.SetControllerFactory(factory);
}
More info can be found here. The blogger shows you exactly the error that you are seeing and then fixes it.
Ok, after searching Google, here and several ASP/MVC forums I am bound to have to ask what the hell I am doing wrong here.
I have a good start to my application, an ok understanding of DI, IoC and am using the Repository, Service and UnitOfWork patterns. When I attempt to load a controller that needs the DI from Unity, it's as if unity is not resolving any of the registered items, or that I have done it poorly. From all the examples I can see for this version (not the version that creates the Bootstrap.cs file that is then called from Global.asax) I am doing what others have done with no love from Unity.
My core question is: Have I setup/configured Unity to inject the items into the controller constructor as needed or not. If I have, any ideas why it's not working like examples I have seen?
I keep getting the error that the AssetController needs to have a parameterless public constructor. If I add one, then it uses it without the DI and if I don't add one, then it yells about not having it.
Thanks, code below.
UnityConfig.cs
namespace CARS.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<IDataContext, CARSDEMOContext>(new PerRequestLifetimeManager())
.RegisterType<IAssetService, AssetService>()
.RegisterType<IUnitOfWork, UnitOfWork>()
.RegisterType<IRepository<Asset>, Repository<Asset>>();
//.RegisterType<AssetController>(new InjectionConstructor(typeof(IAssetService), typeof(IUnitOfWork)));
}
}
}
AssetController.cs (constructor portion where I am doing the injection params)
namespace CARS.web.Controllers
{
public class AssetController : Controller
{
private readonly IAssetService _assetService;
private readonly IUnitOfWork _unitOfWork;
public AssetController(IAssetService assetService, IUnitOfWork unitOfWork)
{
_assetService = assetService;
_unitOfWork = unitOfWork;
}
//other methods for CRUD etc stripped for brevity
}
}
IAssetService.cs (first param is the assetService )
namespace CARS.service
{
public interface IAssetService : IService<Asset>
{
Task<IEnumerable<Asset>> GetAsync();
Task<Asset> FindAsync(Guid id);
Asset Add(Asset asset);
Asset Update(Asset asset);
void Remove(Guid id);
}
}
AssetService.cs (concrete implementation for IAssetService interaction)
namespace CARS.service
{
public class AssetService : Service<Asset>, IAssetService
{
private readonly IRepositoryAsync<Asset> _repository;
public AssetService(IRepositoryAsync<Asset> repository) : base(repository)
{
_repository = repository;
}
public Task<IEnumerable<Asset>> GetAsync()
{
//return _repository.Query().SelectAsync();
return _repository.Query().SelectAsync();
}
public Task<Asset> FindAsync(Guid id)
{
return _repository.FindAsync(id);
}
public Asset Add(Asset asset)
{
_repository.Insert(asset);
return asset;
}
public Asset Update(Asset asset)
{
_repository.Update(asset);
return asset;
}
public void Remove(Guid id)
{
_repository.Delete(id);
}
}
}
IUnitOfWork.cs (this is from Long Le's Generic UofW and Repository - http://genericunitofworkandrepositories.codeplex.com/)
namespace Repository.Pattern.UnitOfWork
{
public interface IUnitOfWork : IDisposable
{
int SaveChanges();
Task<int> SaveChangesAsync();
void Dispose(bool disposing);
IRepository<TEntity> Repository<TEntity>() where TEntity : IObjectState;
void BeginTransaction();
bool Commit();
void Rollback();
}
}
UnitOfWork.cs (again from Long Le's framework)
namespace Repository.Pattern.Ef6
{
public class UnitOfWork : IUnitOfWork, IUnitOfWorkAsync
{
#region Private Fields
private readonly IDataContextAsync _dataContext;
private bool _disposed;
private ObjectContext _objectContext;
private Dictionary<string, object> _repositories;
private DbTransaction _transaction;
#endregion Private Fields
#region Constuctor/Dispose
public UnitOfWork(IDataContextAsync dataContext)
{
_dataContext = dataContext;
}
public void Dispose()
{
if (_objectContext != null && _objectContext.Connection.State == ConnectionState.Open)
_objectContext.Connection.Close();
Dispose(true);
GC.SuppressFinalize(this);
}
public virtual void Dispose(bool disposing)
{
if (!_disposed && disposing)
_dataContext.Dispose();
_disposed = true;
}
#endregion Constuctor/Dispose
public int SaveChanges()
{
return _dataContext.SaveChanges();
}
public IRepository<TEntity> Repository<TEntity>() where TEntity : IObjectState
{
return RepositoryAsync<TEntity>();
}
public Task<int> SaveChangesAsync()
{
return _dataContext.SaveChangesAsync();
}
public Task<int> SaveChangesAsync(CancellationToken cancellationToken)
{
return _dataContext.SaveChangesAsync(cancellationToken);
}
public IRepositoryAsync<TEntity> RepositoryAsync<TEntity>() where TEntity : IObjectState
{
if (_repositories == null)
_repositories = new Dictionary<string, object>();
var type = typeof (TEntity).Name;
if (_repositories.ContainsKey(type))
return (IRepositoryAsync<TEntity>) _repositories[type];
var repositoryType = typeof (Repository<>);
_repositories.Add(type, Activator.CreateInstance(repositoryType.MakeGenericType(typeof (TEntity)), _dataContext, this));
return (IRepositoryAsync<TEntity>) _repositories[type];
}
#region Unit of Work Transactions
public void BeginTransaction()
{
_objectContext = ((IObjectContextAdapter) _dataContext).ObjectContext;
if (_objectContext.Connection.State != ConnectionState.Open)
{
_objectContext.Connection.Open();
_transaction = _objectContext.Connection.BeginTransaction();
}
}
public bool Commit()
{
_transaction.Commit();
return true;
}
public void Rollback()
{
_transaction.Rollback();
((DataContext)_dataContext).SyncObjectsStatePostCommit();
}
#endregion
// Uncomment, if rather have IRepositoryAsync<TEntity> IoC vs. Reflection Activation
//public IRepositoryAsync<TEntity> RepositoryAsync<TEntity>() where TEntity : EntityBase
//{
// return ServiceLocator.Current.GetInstance<IRepositoryAsync<TEntity>>();
//}
}
}
Updated to include the SetResolver info from UnityMvcActivator.cs
using System.Linq;
using System.Web.Mvc;
using Microsoft.Practices.Unity.Mvc;
[assembly: WebActivatorEx.PreApplicationStartMethod(typeof(CARS.web.App_Start.UnityWebActivator), "Start")]
namespace CARS.web.App_Start
{
/// <summary>Provides the bootstrapping for integrating Unity with ASP.NET MVC.</summary>
public static class UnityWebActivator
{
/// <summary>Integrates Unity when the application starts.</summary>
public static void Start()
{
var container = UnityConfig.GetConfiguredContainer();
FilterProviders.Providers.Remove(FilterProviders.Providers.OfType<FilterAttributeFilterProvider>().First());
FilterProviders.Providers.Add(new UnityFilterAttributeFilterProvider(container));
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
// TODO: Uncomment if you want to use PerRequestLifetimeManager
Microsoft.Web.Infrastructure.DynamicModuleHelper.DynamicModuleUtility.RegisterModule(typeof(UnityPerRequestHttpModule));
}
}
}
I have read/tried the following info/data and nothing has fixed it:
The type IUserStore`1 does not have an accessible constructor
How to add MVC 5 authentication to Unity IoC?
Types not resolving with Unity [MVC 5]
I have ready where one must write a ControllerFactory for Unity to be able to do this, but that seems quite a bit of work when all the examples I have found simply have the config registered, and the injection apparently happening on the controllers and other classes as need.
And finally the error:
The following server error was encountered:
An error occurred when trying to create a controller of type 'CARS.web.Controllers.AssetController'. Make sure that the controller has a parameterless public constructor.Details are:
at System.Web.Mvc.DefaultControllerFactory.DefaultControllerActivator.Create(RequestContext requestContext, Type controllerType) at System.Web.Mvc.DefaultControllerFactory.CreateController(RequestContext requestContext, String controllerName) at System.Web.Mvc.MvcHandler.ProcessRequestInit(HttpContextBase httpContext, IController& controller, IControllerFactory& factory) at System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, Object state) at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionSte p.Execute() at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)
Thanks
You need to set the DependencyResolver. I cant see the code in the example you provided where this is done.
Once setting up your UnityContainer and registering your types, you need to set the System.Web.MVC.DependencyResolver.
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
You may have missed (like I did) to register the async types in UnityConfig.cs
Check if you have this:
container.RegisterType<IUnitOfWork, UnitOfWork>(new PerRequestLifetimeManager())
.RegisterType<IUnitOfWorkAsync, UnitOfWork>(new PerRequestLifetimeManager())
.RegisterType<IDataContextAsync, SomeDBContext>(new PerRequestLifetimeManager())
.RegisterType<IDataContext, SomeDBContext>(new PerRequestLifetimeManager())
.RegisterType<ISomeService, SomeService>(new PerRequestLifetimeManager())
.RegisterType<IRepositoryAsync<Some>, Repository<Some>>(new PerRequestLifetimeManager());
1:
Uncomment in file UnityMvcActivator this line:
Microsoft.Web.Infrastructure.DynamicModuleHelper.DynamicModuleUtility.RegisterModule(typeof(UnityPerRequestHttpModule));
2:
Basic registration with Unity + UnitOfwork + Repository
this must exists in file: UnityConfig:
container.RegisterType<IDataContextAsync, KlussendirectContext>(new PerRequestLifetimeManager());
container.RegisterType<IDataContext, KlussendirectContext>(new PerRequestLifetimeManager());
container.RegisterType<IUnitOfWork, UnitOfWork>(new PerRequestLifetimeManager());
container.RegisterType<IUnitOfWorkAsync, UnitOfWork>(new PerRequestLifetimeManager());
3:
When you use Dependency Injection in a controller(api) then a parameter less constructor should exists:
e.g.
public MyNameController() : base(){}
If followed those steps, it should work (Edit, Insert, Delete, etc..)
I am using Ninject together with ASP.NET MVC 4. I am using repositories and want to do constructor injection to pass in the repository to one of the controllers.
Here is my context object (EntityFramework) that implements my StatTracker interface:
public class StatTrackerRepository : IStatTrackerRepository
{
private GolfStatTrackerEntities _ctx;
public StatTrackerRepository(GolfStatTrackerEntities ctx)
{
_ctx = ctx;
}
public IQueryable<Facility> GetFacilites()
{
return _ctx.Facilities;
}
}
This is my Repository interface:
public interface IStatTrackerRepository
{
IQueryable<Facility> GetFacilites();
}
Which then calls my Home Controller:
public class HomeController : Controller
{
public IStatTrackerRepository _repo { get; set; }
public HomeController(IStatTrackerRepository repo)
{
_repo = repo;
}
public ActionResult Index()
{
var facilities = _repo.GetFacilites().ToList();
return View(facilities);
}
}
The page loads properly, however, once the page is loaded, it immedately uses an angularjs Controller which calls the $http method:
function facilityIndexController($scope, $http) {
$scope.data = [];
$http({ method: 'GET', url: '/api/facility' }).
success(function(result) {
angular.copy(result.data, $scope.data);
}).error(function() {
alert("Could not load facilities");
});
}
...which calls the following API controller:
public class FacilityController : ApiController
{
public IStatTrackerRepository _repo { get; set; }
public GolfStatTrackerEntities ctx { get; set; }
//public FacilityController()
//{
// _repo = new StatTrackerRepository(ctx);
//}
public FacilityController(IStatTrackerRepository repo)
{
_repo = repo;
}
public IEnumerable<Facility> Get()
{
var facilities = _repo.GetFacilites().ToList();
return facilities;
}
}
....where it falls into the error function of the angular $http call because the FacilityController(IStatTrackerRepository repo) is never ran.
I have tried using a parameterless contstructor that instantiates a StatTrackerRepository(ctx) for FacilityController(), however, I get a NullReferenceException when I do so.
My Ninject config is as follows:
private static IKernel CreateKernel()
{
var kernel = new StandardKernel();
try
{
kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
RegisterServices(kernel);
//GlobalConfiguration.Configuration.DependencyResolver =
// new NinjectResolver(kernel);
return kernel;
}
catch
{
kernel.Dispose();
throw;
}
}
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<GolfStatTrackerEntities>().To<GolfStatTrackerEntities>().InRequestScope();
kernel.Bind<IStatTrackerRepository>().To<StatTrackerRepository>().InRequestScope();
}
I'm not sure if this is something wrong with Ninject or if there is an issue with how I am implementing Ninject. The injection seems to be working on the initial load of the Home view, however, when it uses angular to call the API, there is a disconnect with Ninject.
Please help.
We ended up using a similar configuration on one of our older projects and realized that we needed to add a little more infrastructure code to our MVC/WebApi App:
NinjectDependencyScope.cs
using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Web.Http.Dependencies;
using Ninject;
using Ninject.Syntax;
namespace YourAppNameSpace
{
public class NinjectDependencyScope : IDependencyScope
{
private IResolutionRoot _resolver;
internal NinjectDependencyScope(IResolutionRoot resolver)
{
Contract.Assert(resolver != null);
_resolver = resolver;
}
public void Dispose()
{
var disposable = _resolver as IDisposable;
if (disposable != null)
{
disposable.Dispose();
}
_resolver = null;
}
public object GetService(Type serviceType)
{
if (_resolver == null)
{
throw new ObjectDisposedException("this", "This scope has already been disposed");
}
return _resolver.TryGet(serviceType);
}
public IEnumerable<object> GetServices(Type serviceType)
{
if (_resolver == null)
{
throw new ObjectDisposedException("this", "This scope has already been disposed");
}
return _resolver.GetAll(serviceType);
}
}
}
NinjectDependencyResolver.cs
using System.Web.Http.Dependencies;
using Ninject;
namespace YourAppNameSpace
{
public class NinjectDependencyResolver : NinjectDependencyScope, IDependencyResolver
{
private readonly IKernel _kernel;
public NinjectDependencyResolver(IKernel kernel)
: base(kernel)
{
_kernel = kernel;
}
public IDependencyScope BeginScope()
{
return new NinjectDependencyScope(_kernel.BeginBlock());
}
}
}
Then we added the following to the NinjectWebCommon.cs file:
public static void RegisterNinject(HttpConfiguration configuration)
{
// Set Web API Resolver
configuration.DependencyResolver = new NinjectDependencyResolver(Bootstrapper.Kernel);
}
And then the following to Global.asax.cs file, Application_Start method:
NinjectWebCommon.RegisterNinject(GlobalConfiguration.Configuration);
This is my controller
public class SuggestionController : ApiController
{
public ISuggestionRepository Repository { get; private set; }
public SuggestionController(ISuggestionRepository repository)
{
this.Repository = repository;
}
// to post suggestion
[HttpPost]
[ActionName("PostSuggestion")]
public HttpResponseMessage PostSuggestion(Suggestion suggestion)
{
var answerCorrect = this.Repository.CreateSuggestion(suggestion);
if (answerCorrect == true)
return Request.CreateResponse(HttpStatusCode.OK);
else
return Request.CreateResponse(HttpStatusCode.Conflict);
}
}
and this is my RegisterServices method in NinjectWebCommon.cs
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<ICompetitionRepository>().To(typeof(CompetitionRepository))
.WithConstructorArgument("serviceContext", new InMemoryDataContext<Competition>());
kernel.Bind<ISubmissionRepository>().To(typeof(SubmissionRepository))
.WithConstructorArgument("serviceContext", new InMemoryDataContext<Submission>());
kernel.Bind<IUserRepository>().To(typeof(UserRepository))
.WithConstructorArgument("serviceContext", new InMemoryDataContext<User>());
kernel.Bind<ISuggestionRepository>().To(typeof(SuggestionRepository))
.WithConstructorArgument("serviceContext", new InMemoryDataContext<Suggestion>());
}
But am getting an exception that my suggestion controller does not have a default constructor and its showing a 500 internal server when am hitting the controller from a client app
I know that we get the exception of controller not having default constructor if the ninject dependency is not working properly but the below is another controller i have implemeneted similar to suggestion controller and its working absolutely fine.
public IUserRepository Repository { get; private set; }
public SSOController(IUserRepository repository)
{
this.Repository = repository;
}
[HttpPost]
[ActionName("PostUser")]
public HttpResponseMessage PostUser([FromBody]string id)
{
var accessToken = id;
var client = new FacebookClient(accessToken);
dynamic result = client.Get("me", new { fields = "name,email" });
string name = result.name;
string email = result.email;
var existingUser = this.Repository.FindByUserIdentity(name);
if (existingUser == null)
{
var newUser = new User
{
Username = name,
Email = email,
};
var success = this.Repository.CreateAccount(newUser);
if (!success)
{
return Request.CreateResponse(HttpStatusCode.InternalServerError);
}
//return created status code as we created the user
return Request.CreateResponse<User>(HttpStatusCode.Created, newUser);
}
return Request.CreateResponse(HttpStatusCode.OK);
}
}
I have no idea where am going wrong. Please let me know if u have any suggestions.
EDIT:
my Global.asax
public class WebApiApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
AuthConfig.RegisterAuth();
GlobalConfiguration.Configuration.IncludeErrorDetailPolicy =
IncludeErrorDetailPolicy.Always;
}
Dependency resolver am using
// Provides a Ninject implementation of IDependencyScope
// which resolves services using the Ninject container.
public class NinjectDependencyScope : IDependencyScope
{
IResolutionRoot resolver;
public NinjectDependencyScope(IResolutionRoot resolver)
{
this.resolver = resolver;
}
public object GetService(Type serviceType)
{
if (resolver == null)
throw new ObjectDisposedException("this", "This scope has been disposed");
return resolver.TryGet(serviceType);
}
public System.Collections.Generic.IEnumerable<object> GetServices(Type serviceType)
{
if (resolver == null)
throw new ObjectDisposedException("this", "This scope has been disposed");
return resolver.GetAll(serviceType);
}
public void Dispose()
{
IDisposable disposable = resolver as IDisposable;
if (disposable != null)
disposable.Dispose();
resolver = null;
}
}
// This class is the resolver, but it is also the global scope
// so we derive from NinjectScope.
public class NinjectDependencyResolver : NinjectDependencyScope, IDependencyResolver
{
IKernel kernel;
public NinjectDependencyResolver(IKernel kernel)
: base(kernel)
{
this.kernel = kernel;
}
public IDependencyScope BeginScope()
{
return new NinjectDependencyScope(kernel.BeginBlock());
}
}
and calling it in CreateKernel() method in NinjectWebCommon
private static IKernel CreateKernel()
{
var kernel = new StandardKernel();
kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
RegisterServices(kernel);
// Install our Ninject-based IDependencyResolver into the Web API config
GlobalConfiguration.Configuration.DependencyResolver = new NinjectDependencyResolver(kernel);
return kernel;
}
Suggestion Repository
public class SuggestionRepository : Repository<Suggestion>, ISuggestionRepository
{
public SuggestionRepository(IServiceContext<Suggestion> servicecontext)
: base(servicecontext)
{ }
public bool CreateSuggestion(Suggestion suggestion)
{
this.ServiceContext.Create(suggestion);
this.ServiceContext.Save();
return true;
}
}
ISuggestionRepository
public interface ISuggestionRepository
{
bool CreateSuggestion(Suggestion suggestion);
}
Repository
public abstract class Repository<T>
{
public IServiceContext<T> ServiceContext { get; private set; }
public Repository(IServiceContext<T> serviceContext)
{
this.ServiceContext = serviceContext;
}
}
IserviceContext
public interface IServiceContext<T>
{
IQueryable<T> QueryableEntities { get; }
void Create(T entity);
void Update(T entity);
void Delete(T entity);
void Save();
}
Since you're using WebApi, you will need to use the WebApi extension for Ninject. Unfortunately, the current Ninject.WebApi nuget package is out of date, and doesn't work with the released version of WebApi.
Temporarily, until Remo gets around to updating Ninject.WebApi to the release version, you can use Ninject.WebApi-RC http://nuget.org/packages/Ninject.Web.WebApi-RC
http://www.eyecatch.no/blog/2012/06/using-ninject-with-webapi-rc/
EDIT:
To recap the information discussed in comments, Here are the recommendations:
1) Use Ninject.MVC3 and Ninject.Web.WebApi (but use Ninject.Web.WebApi-RC until the official is updated) as discussed above. Do not use a custom DependencyResolver, and let Ninject.Web.Mvc and .WebApi do their job.
2) Change your bindings to this:
kernel.Bind<ICompetitionRepository>().To<CompetitionRepository>();
... similar bindings
3) Add a generic binding for your ServiceContext
kernel.Bind(typeof(IServiceContext<>)).To(typeof(InMemoryDataContext<>));
I think the problem is you're using the ApiController.
Controllers and apiControllers are using a different dependancy injection container.
Both of them however expose the same methods.
If the working controller is inheriting the Controller class then that's your cause.
For a work around take a look at
this topic
I have faced the same issue.
This is how I rectified:
I created a WebContainerManager which is just a static wrapper around container.
Static container wrappers useful when you don't control instantiation and can't rely on injection - e.g. action filter attributes
public static class WebContainerManager
{
public static IKernel GetContainer()
{
var resolver = GlobalConfiguration.Configuration.DependencyResolver as NinjectDependencyResolver;
if (resolver != null)
{
return resolver.Container;
}
throw new InvalidOperationException("NinjectDependencyResolver not being used as the MVC dependency resolver");
}
public static T Get<T>()
{
return GetContainer().Get<T>();
}
}
Inside your controller, call your empty constructor like this with no parameters:
public SuggestionController() : this(WebContainerManager.Get<ISuggestionRepository>())
{
}
This should work.
This technique i got from the book on MVC4 by Jamie Kurtz #jakurtz.
You probably need to do some dependency injection so you can inject the ISuggestionRepository parameter on your SuggestionController constructor. To do that you need to override methods in the DefaultControllerFactory class to customize the creation of controllers. Since you are using NInject, you can have something like:
public class NInjectControllerFactory : DefaultControllerFactory
{
private IKernel kernel = new StandardKernel(new CustomModule());
protected override IController GetControllerInstance(System.Web.Routing.RequestContext requestContext, Type controllerType)
{
return controllerType == null ? null : (IController)kernel.Get(controllerType);
}
public class CustomModule : NinjectModule
{
public override void Load()
{
this.Bind<ICompetitionRepository>().To(typeof(CompetitionRepository))
.WithConstructorArgument("serviceContext", new InMemoryDataContext<Competition>());
this.Bind<ISubmissionRepository>().To(typeof(SubmissionRepository))
.WithConstructorArgument("serviceContext", new InMemoryDataContext<Submission>());
this.Bind<IUserRepository>().To(typeof(UserRepository))
.WithConstructorArgument("serviceContext", new InMemoryDataContext<User>());
this.Bind<ISuggestionRepository>().To(typeof(SuggestionRepository))
.WithConstructorArgument("serviceContext", new InMemoryDataContext<Suggestion>());
}
}
}
Then in your Global.asax.cs, you can add a line to swap out the controller factory
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
ControllerBuilder.Current.SetControllerFactory(new NInjectControllerFactory());
}
WCF services. My 1st attempt at IoC with WCF. Calling service from Console app to test. Funny thing is I thought these services were working so I was using them to provide data to test a POC I was working on...little did I know I'd first end up fixing the services!
(Debugging using Cassini)
Versions I'm using:
FluentNHibernate 1.1.0.685
NHibernate 2.1.2.4000
Ninject 2.2.0.0
Ninject.Extensions.Wcf 2.2.0.0
.NET Framework 3.5
This is one of the examples I used as a reference: Pieter De Rycke's Blog
Almost every post I found on SO deals with MVC...I assume my issue is slightly different since this is WCF not MVC.
The Exception:
Error activating IAuditRepository
No matching bindings are available, and the type is not self-bindable.
Activation path:
2) Injection of dependency IAuditRepository into parameter auditRepository of constructor of type ShotService
1) Request for ShotService
Suggestions:
1) Ensure that you have defined a binding for IAuditRepository.
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.
Console app failing code: (fails on last line)
ShotServiceClient shotSvc = new ShotServiceClient();
LookupShotAdministeredRequest request = new LookupShotAdministeredRequest();
request.ClientId = "128";
request.ClinicId = "289";
request.RequestingUserId = "1";
List<ShotsAdministeredContract> shots = shotSvc.LookupShotAdministered(request).ShotsAdministered;
The Code:
Global.asax.cs
public class Global : NinjectWcfApplication
{
protected override IKernel CreateKernel()
{
var modules = new INinjectModule[]
{
new NHibernateModule(),
new ServiceModule(),
new RepositoryModule()
};
return new StandardKernel(modules);
}
}
NHibernateSessionFactoryProvider.cs
public class NhibernateSessionFactoryProvider : Provider<ISessionFactory>
{
protected override ISessionFactory CreateInstance(IContext context)
{
var sessionFactory = new NhibernateSessionFactory();
return sessionFactory.GetSessionFactory();
}
}
NHibernateSessionFactory.cs
public class NhibernateSessionFactory
{
public ISessionFactory GetSessionFactory()
{
ISessionFactory fluentConfiguration = Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2008
.ConnectionString(ConfigurationManager.ConnectionStrings["DefaultConnectionString"].ConnectionString)
.Cache(c => c
.UseQueryCache()
.ProviderClass<HashtableCacheProvider>())
.ShowSql())
.Mappings(m => m.FluentMappings.AddFromAssemblyOf<AppointmentMap>()
.Conventions.AddFromAssemblyOf<PrimaryKeyConvention>())
.BuildSessionFactory();
return fluentConfiguration;
}
}
NHibernateModule.cs
public class NHibernateModule : NinjectModule
{
public override void Load()
{
Bind<ISessionFactory>().ToProvider<NhibernateSessionFactoryProvider>().InSingletonScope();
Bind<ISession>().ToMethod(context => context.Kernel.Get<ISessionFactory>().OpenSession()).InRequestScope();
}
}
RepositoryModule.cs
public class RepositoryModule : NinjectModule
{
public override void Load()
{
Bind<IAuditRepository>().To<AuditRepository>();
.
.
.
Bind<IShotAdministeredRepository>().To<ShotAdministeredRepository>();
}
}
ServiceModule.cs
public class ServiceModule : NinjectModule
{
public override void Load()
{
Bind<IAuditService>().To<AuditService>();
.
.
.
Bind<IShotService>().To<ShotService>();
}
}
NinjectInstanceProvider.cs
public class NinjectInstanceProvider : IInstanceProvider
{
private Type serviceType;
private IKernel kernel;
public NinjectInstanceProvider(IKernel kernel, Type serviceType)
{
this.kernel = kernel;
this.serviceType = serviceType;
}
public object GetInstance(InstanceContext instanceContext)
{
return this.GetInstance(instanceContext, null);
}
public object GetInstance(InstanceContext instanceContext, Message message)
{
//Create the instance with your IoC container of choice...here we're using Ninject
return kernel.Get(this.serviceType);
}
public void ReleaseInstance(InstanceContext instanceContext, object instance)
{
}
}
NinjectBehaviorAttribute.cs
public class NinjectBehaviorAttribute : Attribute, IServiceBehavior
{
public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
{
}
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
Type serviceType = serviceDescription.ServiceType;
IInstanceProvider instanceProvider = new NinjectInstanceProvider(new StandardKernel(), serviceType);
foreach (ChannelDispatcher dispatcher in serviceHostBase.ChannelDispatchers)
{
foreach (EndpointDispatcher endpointDispatcher in dispatcher.Endpoints)
{
DispatchRuntime dispatchRuntime = endpointDispatcher.DispatchRuntime;
dispatchRuntime.InstanceProvider = instanceProvider;
}
}
}
public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
}
}
IAuditRepository.cs
public interface IAuditRepository : IRepository<Audit>
{
}
AuditRepository.cs
public class AuditRepository : Repository<Audit>, IAuditRepository
{
public AuditRepository(ISession session) : base(session) { }
}
ShotRepository.cs
public class ShotRepository : Repository<Shot>, IShotRepository
{
public ShotRepository(ISession session) : base(session) { }
}
ShotService.svc.cs
[NinjectBehaviorAttribute]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
public class ShotService : IShotService
{
#region Members
private IAuditRepository _auditRepository;
private IClientRepository _clientRepository;
private IClinicRepository _clinicRepository;
private IShotRepository _repository;
private IShotAdministeredRepository _administeredRepository;
private IShotCostRepository _costRepository;
private IUserRepository _userRepository;
#endregion
#region Constructors
public ShotService(IAuditRepository auditRepository, IClientRepository clientRepository, IClinicRepository clinicRepository, IShotRepository repository, IShotAdministeredRepository administeredRepository, IShotCostRepository costRepository, IUserRepository userRepository)
{
_auditRepository = auditRepository;
_clientRepository = clientRepository;
_clinicRepository = clinicRepository;
_repository = repository;
_administeredRepository = administeredRepository;
_costRepository = costRepository;
_userRepository = userRepository;
}
#endregion
#region IShotService Members
.
.
.
public ListAdministeredShotsResponse LookupShotAdministered(LookupShotAdministeredRequest request)
{
ListAdministeredShotsResponse response = new ListAdministeredShotsResponse();
try
{
UserService userService = new UserService(_userRepository, _auditRepository);
User requestingUser = userService.Read(Convert.ToInt32(request.RequestingUserId));
if (userService.HasPermission(requestingUser, Permissions.ScheduleAppointments))
{
ShotAdministeredService service = new ShotAdministeredService(_administeredRepository, _auditRepository);
//Guts of method go here...irrelevant to current issue
}
else
{
throw new InvalidPermissionException("Requesting user does not have sufficient permissions to complete the request.");
}
}
catch (Exception ex)
{
response.FailureReason = ex.Message;
}
return response;
}
.
.
.
#endregion
}
I put a break point in CreateKernel(), it has not been hit. I also put a break point in Load() in NHibernateModule.cs, that break point has also not been hit. <-- Correction...Cassini was "not responding" so I guess I wasn't really debugging ALL of my code. I just did an End Task on Cassini and re-ran the debugger on my services...My break point in CreateKernel() was hit as well as my break point in Load(). My main issue still exists, but at least I know this code is being executed.
You are using Ninject.Extensions.Wcf and you do an own integration into Wcf at the same time. There are two kernel instances involved one of which is configured and the other one not. You should decide which integration to use and configure that kernel properly.