I have a little experience working with Dependency Injection using Xamarin.Forms, but not in WebApi, What I want is send data through my Interface and execute inside of my Class which is implementing that Interface, there's what I have :
public interface IRepository
{
IHttpActionResult SendContext(user user);
IHttpActionResult GetContextData(int id);
}
public class ContextGoneBase : ApiController,IRepository
{
public IHttpActionResult GetContextData(int id)
{
try
{
using (var context = new GoneContext())
{
var result = context.user.Where(a => a.id_user == id).Select(w =>
new { w.user_name, w.cellphone_number, w.user_kind, w.CEP, w.area.area_name, w.district, w.city.city_name, w.city.state.state_name });
var list = result.ToList();
if (list != null)
{
return Ok(list);
}
else
{
return BadRequest();
}
}
}
catch (Exception)
{
return BadRequest();
}
}
And Inside of my controller I was trying to do something like that:
[Route("86538505")]
public IHttpActionResult GetData(int id, IRepository repo)
{
this._repo = repo;
var result = _repo.GetContextData(id);
return result;
}
But, it fails! Thanks!
You should instead pass the IRepository as a parameter to the constructor
Set the field _repo of type IRepository to the value of the parameter passed.
public ContextGoneBase (IRepository repository){ //Constructor
_repo = repository;
}
.And then use an IOC container like Unity to instantiate the controller with the right parameters.For example after you install Unity using nuget you will have a UnityConfig class file and there you can register your repository type.For example if your repository is of type Repository then
public static class UnityConfig
{
public static void RegisterComponents()
{
// register all your components with the container here
// it is NOT necessary to register your controllers
// e.g. container.RegisterType<ITestService, TestService>();
var container = new UnityContainer();
container.RegisterType<IRepository,Repository>();
GlobalConfiguration.Configuration.DependencyResolver = new UnityDependencyResolver(container);
}
}
Now in Global.asax call this method:
protected void Application_Start()
{
UnityConfig.RegisterComponents();
}
Related
I'm trying to write a generic command bus (Part of class library) that uses different commands and handlers in each of my services.
The following code produces the following exception:
System.Exception: Command does not have any handler RegisterUserCommand
I was under the impression passing the the ExecutingAssemblies of my UserService would allow the Container to resolve the handler in my UserService but apparently not.
Am I doing something wrong?
CommandBus:
public interface ICommandBus
{
void Send<T>(T Command) where T : ICommand;
}
public class CommandBus : ICommandBus
{
private IContainer Container { get; set; }
public CommandBus(Assembly assembly)
{
Container = new CommandBusContainerConfig().Configure(assembly);
}
public void Send<TCommand>(TCommand command) where TCommand : ICommand
{
var handlers = Container.Resolve<IEnumerable<ICommandHandler<TCommand>>>().ToList();
if (handlers.Count == 1)
{
handlers[0].Handle(command);
}
else if (handlers.Count == 0)
{
throw new System.Exception($"Command does not have any handler {command.GetType().Name}");
}
else
{
throw new System.Exception($"Too many registred handlers - {handlers.Count} for command {command.GetType().Name}");
}
}
}
ContainerBuilder:
public class CommandBusContainerConfig : IContainerConfig
{
public IContainer Configure(Assembly executingAssembly)
{
var builder = new ContainerBuilder();
builder.RegisterAssemblyTypes(executingAssembly)
.Where(x => x.IsAssignableTo<ICommandHandler>())
.AsImplementedInterfaces();
builder.Register<Func<Type, ICommandHandler>>(c =>
{
var ctx = c.Resolve<IComponentContext>();
return t =>
{
var handlerType = typeof(ICommandHandler<>).MakeGenericType(t);
return (ICommandHandler)ctx.Resolve(handlerType);
};
});
return builder.Build();
}
}
In my UserService(ASP.Net Core 3), which is a different project that references the above CommandBus:
public class RegisterUserCommand : ICommand
{
public readonly string Name;
public readonly Address Address;
public string MobileNumber;
public string EmailAddress;
public RegisterUserCommand(Guid messageId, string name, string mobileNumber, string emailAddress, Address address)
{
Name = name;
Address = address;
MobileNumber = mobileNumber;
EmailAddress = emailAddress;
}
CommandHandler:
public class RegisterUserComnmandHandler : ICommandHandler<RegisterUserCommand>
{
public void Handle(RegisterUserCommand command)
{
Console.WriteLine($"Create user {command.Name} {command.MobileNumber} - handler");
}
}
Startup:
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<ICommandBus>(new CommandBus(Assembly.GetExecutingAssembly()));
}
Controller:
private readonly ICommandBus _commandBus;
public UsersController(ICommandBus commandBus) {
_commandBus = commandBus;
}
// POST api/values
[HttpPost]
public async Task<IActionResult> Post([FromBody]RegisterUserCommand command)
{
if (ModelState.IsValid)
{
CommandBus commandBus = new CommandBus(Assembly.GetExecutingAssembly());
commandBus.Send(command);
_commandBus.Send(Command); //Same result as above
// return result
return Ok(command);
}
return BadRequest();
}
Thanks,
The main error is here :
builder.RegisterAssemblyTypes(executingAssembly)
.Where(x => x.IsAssignableTo<ICommandHandler>())
.AsImplementedInterfaces();
RegisterUserComnmandHandler is not a ICommandHandler but a ICommandHandler<RegisterUserCommand>. Instead of IsAssignableTo<> method you can use the IsClosedTypeOf which is an Autofac extension which do exactly what you can.
builder.RegisterAssemblyTypes(executingAssembly)
.Where(x => x.IsClosedTypeOf(typeof(ICommandHandler<>)))
.AsImplementedInterfaces();
By the way, in your code sample you are using another Container. Most of the time it is always simple to have a single container for the whole application. To get things organised you can use autofac module. You are also resolving straight from the container and not using scope this means that your instance graph won't be disposed at the end of the operation but will stay for the whole lifetime of the container.
In your controller, I saw that you are building a new CommandBus for each request, which will create a new container. Building a new container is a heavy operation and you should avoid doing it often but only once of the startup of the application.
Also I don't get the point of this registration :
builder.Register<Func<Type, ICommandHandler>>(c =>
{
var ctx = c.Resolve<IComponentContext>();
return t =>
{
var handlerType = typeof(ICommandHandler<>).MakeGenericType(t);
return (ICommandHandler)ctx.Resolve(handlerType);
};
});
It doesn't looks you need it and it seems useless to me
This took me a while to figure out. But my CommandHandler interface was incorrectly defined. It should look like:
public interface ICommandHandler { }
public interface ICommandHandler<T> : ICommandHandler where T : ICommand
{
void Handle(T command);
}
}
When trying to resolve the CommandHandler in the Autofac configuration class, the .Where(x => x.IsAssignableTo<ICommandHandler>()) was failing because the class was assignable to ICommandHandle<T> not ICommandHandler
I'm trying to test my project. I have never used tests before and I am starting to learn I would like a help, in the simplest case I want test this public ActionResult Index() but I don't know how to Inject those dependencies.
Controller:
Controller:
public class WorkPlacesController : Controller
{
private readonly IWorkPlaceService workPlaceService;
public WorkPlacesController(IWorkPlaceService workPlaceService)
{
this.workPlaceService = workPlaceService;
}
// GET: WorkPlaces
public ActionResult Index()
{
var workPlaces = workPlaceService.GetWorkPlaces(includedRelated:
true);
return View(workPlaces);
}
}
Here is my Service
Service
public class WorkPlaceService : IWorkPlaceService
{
private readonly IWorkPlaceRepository workPlacesRepository;
private readonly IUnitOfWork unitOfWork;
public WorkPlaceService(IWorkPlaceRepository workPlacesRepository, IUnitOfWork unitOfWork)
{
this.workPlacesRepository = workPlacesRepository;
this.unitOfWork = unitOfWork;
}
}
public interface IWorkPlaceService
{
IEnumerable<WorkPlace> GetWorkPlaces(string workPlaceDescription = null, bool includedRelated = true);
}
And my Repository
Repository
public class WorkPlaceRepository : RepositoryBase<WorkPlace>, IWorkPlaceRepository
{
public WorkPlaceRepository(IDbFactory dbFactory)
: base(dbFactory) { }
public WorkPlace GetWorkPlaceByDescription(string workPlaceDescription)
{
var workPlace = this.DbContext.WorkPlaces.Where(c => c.Description == workPlaceDescription).FirstOrDefault();
return workPlace;
}
}
public interface IWorkPlaceRepository : IRepository<WorkPlace>
{
WorkPlace GetWorkPlaceByDescription(string workPlaceDescription);
}
Factory
public class DbFactory : Disposable, IDbFactory
{
AgendaEntities dbContext;
public AgendaEntities Init()
{
return dbContext ?? (dbContext = new AgendaEntities());
}
protected override void DisposeCore()
{
if (dbContext != null)
dbContext.Dispose();
}
}
I tried to do something like this:
public void BasicIndexTest()
{
// Arrange
var mockRepository = new Mock<IWorkPlaceService>();
var controller = new WorkPlacesController(mockRepository.Object);
// Act
ActionResult actionResult = controller.Index() as ViewResult;
// Assert
Assert.IsInstanceOfType(actionResult, typeof(List<WorkPlace>));
}
How do I inject in this controller the data needed to go in the database and bring the results?
I Want test this public ActionResult Index() but I don't know how to Inject those dependencies.
Mock the behavior of required dependencies of the controller for the test and assert the desired behavior when the test is exercised.
For example, based on what you have done so far
public void BasicIndexTest() {
// Arrange
var mockService = new Mock<IWorkPlaceService>();
var workPlaces = new List<WorkPlace>() {
new WorkPlace()
};
mockService
.Setup(_ => _.GetWorkPlaces(It.IsAny<string>(), It.IsAny<bool>()))
.Returns(workPlaces);
var controller = new WorkPlacesController(mockService.Object);
// Act
var actionResult = controller.Index() as ViewResult;
// Assert
Assert.IsNotNull(actionResult);
var model = actionResult.Model;
Assert.IsNotNull(model)
Assert.IsInstanceOfType(model, typeof(List<WorkPlace>));
Assert.AreEqual(workPlaces, model);
}
Only the IWorkPlaceService was needed for the testing of Index action, but fake data was needed for the invocation of the GetWorkPlaces method. So the mock was configured to return a list of objects when called and pass it to the view result.
I have been working on converting my tightly coupled method into one that can be unit tested and have sought some advice on here. I now have my method passing its unit test thanks to some advice - however I now find that I cant call the method from my application. I used to access my GetAllProductsFromCSV() method from the controller with the following:
public ActionResult Index()
{
var products = new ProductsCSV();
List<ProductItem> allProducts = products.GetAllProductsFromCSV();
foreach (var product in allProducts)
{
if (string.IsNullOrEmpty(product.ImagePath))
{
product.ImagePath = "blank.jpg";
}
}
return View(allProducts);
}
The Method was as follows:
public class ProductsCSV
{
public List<ProductItem> GetAllProductsFromCSV()
{
var productFilePath = HttpContext.Current.Server.MapPath(#"~/CSV/products.csv");
String[] csvData = File.ReadAllLines(productFilePath);
List<ProductItem> result = new List<ProductItem>();
foreach (string csvrow in csvData)
{
var fields = csvrow.Split(',');
ProductItem prod = new ProductItem()
{
ID = Convert.ToInt32(fields[0]),
Description = fields[1],
Item = fields[2][0],
Price = Convert.ToDecimal(fields[3]),
ImagePath = fields[4],
Barcode = fields[5]
};
result.Add(prod);
}
return result;
}
}
I have now made the following changes in the ProductCSV class:
public class ProductsCSV
{
private readonly IProductsCsvReader reader;
public ProductsCSV(IProductsCsvReader reader = null)
{
this.reader = reader;
}
public List<ProductItem> GetAllProductsFromCSV()
{
var productFilePath = #"~/CSV/products.csv";
var csvData = reader.ReadAllLines(productFilePath);
var result = parseProducts(csvData);
return result;
}
private List<ProductItem> parseProducts(String[] csvData)
{
List<ProductItem> result = new List<ProductItem>();
foreach (string csvrow in csvData)
{
var fields = csvrow.Split(',');
ProductItem prod = new ProductItem()
{
ID = Convert.ToInt32(fields[0]),
Description = fields[1],
Item = fields[2][0],
Price = Convert.ToDecimal(fields[3]),
ImagePath = fields[4],
Barcode = fields[5]
};
result.Add(prod);
}
return result;
}
Along with the following class & Interface:
public class DefaultProductsCsvReader : IProductsCsvReader
{
public string[] ReadAllLines(string virtualPath)
{
var productFilePath = HostingEnvironment.MapPath(virtualPath);
String[] csvData = File.ReadAllLines(productFilePath);
return csvData;
}
}
public interface IProductsCsvReader
{
string[] ReadAllLines(string virtualPath);
}
As I said, the Unit-Test on method GetAllProductsFromCSV completes successfully now however when I try accessing the method from my controller I get a NullReferenceException on the reader.ReadAllLines call within GetAllProductsFromCSV. It makes sense to me that when I attempt to create an instance of ProductsCSV from within the controller - I am not passing in any parameters... The constructor for the class however requests a IProductsCsvReader. What I cant figure out is how do I actually make the call to the method now? I hope that is clear??
First lets update ProductsCSV to have a backing interface
public interface IProductsCSV {
List<ProductItem> GetAllProductsFromCSV();
}
public class ProductsCSV : IProductsCSV {
//...other code removed for brevity
}
The controller wound now depend on the abstraction introduced above, decoupling it from the concrete implementation from the original controller. Though a simplified example, this allows the controller to be easier to maintain and unit-test in isolation.
public class ProductsController : Controller {
private readonly IProductsCSV products;
public ProductsController(IProductsCSV products) {
this.products = products;
}
public ActionResult Index() {
List<ProductItem> allProducts = products.GetAllProductsFromCSV();
foreach (var product in allProducts) {
if (string.IsNullOrEmpty(product.ImagePath)) {
product.ImagePath = "blank.jpg";
}
}
return View(allProducts);
}
}
Note how the action matched exactly what you had before except for how the products is created.
Finally now that the controller has been refactored for dependency inversion, the framework needs to be configured to be able to inject the dependencies into the the controller when requested.
You can eventually use your library of choice but for this example I am using what they used in documentation
ASP.NET MVC 4 Dependency Injection
Never mind the version. The implementation is transferable.
In the documentation above they used Unity for their IoC container. There are many container libraries available so search for the one you prefer and use that.
public static class BootStrapper {
private static IUnityContainer BuildUnityContainer() {
var container = new UnityContainer();
//Register types with Unity
container.RegisterType<IProductsCSV , ProductsCSV>();
container.RegisterType<IProductsCsvReader, DefaultProductsCsvReader>();
return container;
}
public static void Initialise() {
//create container
var container = BuildUnityContainer();
//grab the current resolver
IDependencyResolver resolver = DependencyResolver.Current;
//create the new resolver that will be used to replace the current one
IDependencyResolver newResolver = new UnityDependencyResolver(container, resolver);
//assign the new resolver.
DependencyResolver.SetResolver(newResolver);
}
}
public class UnityDependencyResolver : IDependencyResolver {
private IUnityContainer container;
private IDependencyResolver resolver;
public UnityDependencyResolver(IUnityContainer container, IDependencyResolver resolver) {
this.container = container;
this.resolver = resolver;
}
public object GetService(Type serviceType) {
try {
return this.container.Resolve(serviceType);
} catch {
return this.resolver.GetService(serviceType);
}
}
public IEnumerable<object> GetServices(Type serviceType) {
try {
return this.container.ResolveAll(serviceType);
} catch {
return this.resolver.GetServices(serviceType);
}
}
}
You would call the above bootstrapper in your start up code.
For example
protected void Application_Start() {
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
Bootstrapper.Initialise(); //<-- configure DI
AppConfig.Configure();
}
So now when ever the framework has to create the ProductsController it will know how to initialize and inject the controller's dependencies.
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());
}