I am trying to implement dependency injection in web api 2 but unable to do so. Getting object reference not set error.
Here is my implementatoin
Model:
public class Product
{
.....
}
Interface:
public interface IProductRepository
{
IEnumerable<Product> GetAll();
.....
}
Interface Implementation:
public class ProductRespository : IProductRepository, IDisposable
{
private ApiContext _context;
public ProductRespository(ApiContext context)
{
this._context = context;
}
public ProductRespository()
{
}
public IEnumerable<Product> GetAll()
{
return _context.Products.OrderBy(o => o.Name);
}
......
}
And Ninjectwebcommon.cs class:
public static class NinjectWebCommon
{
private static readonly Bootstrapper bootstrapper = new Bootstrapper();
public static void Start(){....}
.....
private static IKernel CreateKernel()
{
var kernel = new StandardKernel();
kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
System.Web.Http.GlobalConfiguration.Configuration.DependencyResolver = new Ninject.WebApi.DependencyResolver.NinjectDependencyResolver(kernel);
RegisterServices(kernel);
return kernel;
}
private static void RegisterServices(IKernel kernel)
{
//kernel.Bind<IRepo>().ToMethod(ctx => new Repo("Ninject Rocks!"));
kernel.Bind<ApiContext>().ToSelf().InRequestScope();
kernel.Bind<IProductRepository>().To<ProductRespository>().InRequestScope();
}
}
And finally in my controller ProductController:
public class ProductController : ApiController
{
private IProductRepository _productRepository = null;
public ProductController(IProductRepository productRepository)
{
_productRepository = productRepository;
}
public ProductController()
{
}
public IHttpActionResult GetAllProducts()
{
return Ok(_productRepository.GetAll());
}
}
When getallproducts controller method is hit i get this exception
System.NullReferenceException: 'Object reference not set to an instance of an object.'
I think this is related to your interface in ProductController.
Try like this:
public IProductRepository _productRepository { get; set; }
I had the same problems, but using given codeline helped me / us out.
Related
I want to inject to Hangfire AuthorizationFilter my custom serice and do something with it an i face problem my service is always null.
Owin startup class :
public class Startup
{
public void Configuration(IAppBuilder app )
{
GlobalConfiguration.Configuration
.UseSqlServerStorage("SomeContext")
.UseNinjectActivator(new Bootstrapper().Kernel);
app.UseHangfireDashboard("/hangfire", new DashboardOptions { AuthorizationFilters = new[] { new RestrictiveAuthorizationFilter() } });
app.UseHangfireServer();
}
}
Custom filter :
public class RestrictiveAuthorizationFilter : IAuthorizationFilter
{
[Inject]
public IUserService _userService { get; set; }
public bool Authorize(IDictionary<string, object> owinEnvironment)
{
//do something with _userService but it is always null
return true;
}
}
Ninject kernel :
private static void RegisterServices(IKernel kernel)
{
kernel.Bind(x => { x.From(typeof(BookService).Assembly).SelectAllClasses().EndingWith("Service").BindDefaultInterface(); });
kernel.Bind<LibraryDBContext>().ToSelf().InRequestScope();
kernel.Bind<IBackgroundJobClient>().To<BackgroundJobClient>();
}
I don't see my error could you help me ?
You can pass the kernel as an argument to RestrictiveAuthorizationFilter constructor and ask for the IUserService.
public class RestrictiveAuthorizationFilter : IAuthorizationFilter
{
public IUserService _userService { get; set; }
public RestrictiveAuthorizationFilter(IKernel kernel)
{
_userService = kernel.Get<IUserService>()
}
public bool Authorize(IDictionary<string, object> owinEnvironment)
{
//do something with _userService but it is always null
return true;
}
}
Here is my project responsible for data:
public interface IRepository<T> where T : class
{
IQueryable<T> All();
T GetById(int id);
void Add(T entity);
void Update(T entity);
....
}
EF implement IRepository
public class GenericRepository<T> : IRepository<T> where T : class
{
public GenericRepository() : this(new ApplicationDbContext())
{
}
public GenericRepository(DbContext context)
{
if (context == null)
{
throw new ArgumentException("An instance of DbContext is required to use this repository.", "context");
}
this.Context = context;
this.DbSet = this.Context.Set<T>();
}
protected IDbSet<T> DbSet { get; set; }
protected DbContext Context { get; set; }
public virtual IQueryable<T> All()
{
return this.DbSet.AsQueryable();
}
public virtual T GetById(int id)
{
return this.DbSet.Find(id);
}........
I use unit of work pattern
public interface IUowData : IDisposable
{
IRepository<House> Houses { get; }
IRepository<Floor> Floors { get; }
...
int SaveChanges();
}
And this is his implementation
public class UowData:IUowData
{
private readonly DbContext context;
private readonly Dictionary<Type, object> repositories = new Dictionary<Type, object>();
public UowData(){}
public UowData(DbContext context)
{
this.context = context;
}
private IRepository<T> GetRepository<T>() where T : class
{
if (!this.repositories.ContainsKey(typeof(T)))
{
var type = typeof(GenericRepository<T>);
this.repositories.Add(typeof(T), Activator.CreateInstance(type, this.context));
}
return (IRepository<T>)this.repositories[typeof(T)];
}
public int SaveChanges()
{
return this.context.SaveChanges();
}
public void Dispose()
{
this.context.Dispose();
}
The second project is of type Web API through which I try to access data from database:
public class ArduinoController : ApiController
{
private IEmailSender sender;
private IUowData data;
public ArduinoController(IEmailSender sender, IUowData data)
{
this.sender = sender;
this.data = data;
}
[HttpPost]
[ActionName("PostAlarm")]
public void PostAlarm(dynamic sensorJson)
{
var alartModel = this.data.Sensors.All()
.....
When I try to use Ninject dependancy resolve i get exception:
"The context cannot be used while the model is being created. This exception may be thrown if the context is used inside the OnModelCreating method or if the same context instance is accessed by multiple threads concurrently. Note that instance members of DbContext and related classes are not guaranteed to be thread safe.".
Everything works fine if I fetch one page at a time. I am using a simple tool 'XENU' to fetch multiple pages simultaneously. This is when I get errors with DBContext by fetching multiple pages at a time.
public static class NinjectWebCommon
{
private static readonly Bootstrapper bootstrapper = new Bootstrapper();
public static void Start()
{
DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
bootstrapper.Initialize(CreateKernel);
}
public static void Stop()
{
bootstrapper.ShutDown();
}
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.Http.GlobalConfiguration.Configuration.DependencyResolver = new Ninject.WebApi.DependencyResolver.NinjectDependencyResolver(kernel);
return kernel;
}
private static void RegisterServices(IKernel kernel)
{
EmailSettings emailSettings = new EmailSettings
{
ServerName = Settings.Default.EmailServerName,
...
};
kernel.Bind<IEmailSender>().To<EmailSender>().WithConstructorArgument("settings", emailSettings);
kernel.Bind<IUowData>().To<UowData>().InRequestScope().WithConstructorArgument("context",new ApplicationDbContext());
}
}
.WithConstructorArgument("context",new ApplicationDbContext());
results in one DB Context for the whole application. Remove that and add a binding instead.
.Bind<DbContext>().To<ApplicationDbContext>().InRequestScope();
In MVC4,I inject the Controller by using the Ninject and I want to test the "Index".
Injection of the writing(The controller for injection):
public class NinjectDependencyResolver : IDependencyResolver
{
private IKernel kernel;
public NinjectDependencyResolver()
{
kernel = new StandardKernel();
AddBindings();
}
private void AddBindings()
{
kernel.Bind<IDB>().To<DB>();
}
public object GetService(Type serviceType)
{
return kernel.TryGet(serviceType);
}
public IEnumerable<object> GetServices(Type serviceType)
{
return kernel.GetAll(serviceType);
}
}
The IDB:
public interface IDB
{
IBugTrackRepository iBugTrackRepository { get; }
ICategoryRepository iCategoryRepository { get; }
...
...
IUserRepository iUserRepository { get; }
}
To achieve:
public class DB : IDB
{
public IBugTrackRepository iBugTrackRepository
{
get { return new BugTrackRepository(); }
}
public ICategoryRepository iCategoryRepository
{
get { return new CategoryRepository(); }
}
...
...
public IUserRepository iUserRepository
{
get { return new UserRepository(); }
}
}
To achieve:
public class BugTrackRepository : IBugTrackRepository
{
private DBEntities context = new DBEntities ();
public IQueryable<BugTrack> bugtrack
{
get { return context.BugTrack; }
}
...
//Other database operations...
}
The Controller:
public class HomeController : Controller
{
private IDB repository;
public HomeController(IDB repo)
{
repository = repo;
}
public ActionResult Index()
{
ViewBag.mytitle = "Home Page";
return View();
}
}
The Test Code:
[TestMethod]
public void TestIndex()
{
HomeController controller = new HomeController(??);
ViewResult result = controller.Index() as ViewResult;
Assert.AreEqual("Home Page", result.ViewBag.mytitle);
}
but this test is wrong and I don't konw how to instantiate this Controller.Please help me!Have any questions please leave a message.
Your Home's constructor contains IDB interface, so you need to pass it there.
As you have interface you can use mock objects (https://stackoverflow.com/questions/37359/what-c-sharp-mocking-framework-to-use) to imitate your IDB.
Lets say I have 2 tables. ProductCategory and Product. I have 1 generic repository that can handle both tables:
public class GenericRepository<T> : IRepository<T>
But when using unit of work pattern, am I forced to create a repository for ALL tables in my database?
public interface IUnitOfWork : IDisposable
{
int SaveChanges();
IRepository<ProductCategory> ProductCategoryRepository { get; }
IRepository<Product> ProductRepository { get; }
}
Is there not a way I can add the generic repository to the unit of work class?
You can add a generic method to the IUnitOfWork interface:
public interface IUnitOfWork : IDisposable
{
int SaveChanges();
IRepository<T> Repository<T>();
}
But i don't recommend it. It's smells like Service Locator anti-pattern and SRP violation. Better way is to remove all repositories from the IUnitOfWork interface, because providing access to repository is not UnitOfWork's responsibility. I recommend to separate repository from UnitOfWork and inject their into the consumer by itself.
public class Consumer
{
private readonly IUnitOfWork _unitOfWork;
private readonly IRepository<Product> _products;
public Consumer(IUnitOfWork unitOfWork, IRepository<Product> products)
{
_unitOfWork = unitOfWork;
_products = products;
}
public void Action()
{
var product = _products.GetOne();
product.Name = "new name";
_products.Update(product);
_unitOfWork.SaveChanges();
}
}
UDATE:
UnitOfWork and Repository can share context instance.
Here the sample of code:
public class EfUnitOfWork : IUnitOfWork
{
private readonly DbContext _context;
public EfUnitOfWork(DbContext context)
{
_context = context;
}
public void SaveChanges()
{
_context.SaveChanges();
}
}
public class EfRepository<T> : IRepository<T> where T : class
{
private readonly DbContext _context;
public EfRepository(DbContext context)
{
_context = context;
}
//... repository methods...
}
public class Program
{
public static void Main()
{
//poor man's dependency injection
var connectionString = "northwind";
var context = new DbContext(connectionString);
var unitOfWork = new EfUnitOfWork(context);
var repository = new EfRepository<Product>(context);
var consumer = new Consumer(unitOfWork, repository);
consumer.Action();
}
}
Demonstrating a solution with only one class would be
public class Session : ISession
{
private readonly DbContext _dbContext;
public Session(DbContext dbContext)
{
_dbContext = dbContext;
}
public TEntity Single<TEntity>(Expression<Func<TEntity, bool>> expression) where TEntity : class
{
return _dbContext.Set<TEntity>().SingleOrDefault(expression);
}
public IQueryable<TEntity> Query<TEntity>() where TEntity : class
{
return _dbContext.Set<TEntity>().AsQueryable();
}
public void Commit()
{
try { _dbContext.SaveChanges(); }
catch (DbEntityValidationException ex)
{
var m = ex.ToFriendlyMessage();
throw new DbEntityValidationException(m);
}
}
public void Dispose()
{
_dbContext.Dispose();
}
public void Add<TEntity>(IEnumerable<TEntity> items) where TEntity : class
{
items.ToList().ForEach(Add);
}
public void Add<TEntity>(TEntity item) where TEntity : class
{
_dbContext.Set<TEntity>().Add(item);
}
public void Remove<TEntity>(TEntity item) where TEntity : class
{
_dbContext.Set<TEntity>().Remove(item);
}
public void Remove<TEntity>(Expression<Func<TEntity, bool>> expression) where TEntity : class
{
var items = Query<TEntity>().Where(expression);
Remove<TEntity>(items);
}
public void Remove<TEntity>(IEnumerable<TEntity> items) where TEntity : class
{
items.ToList().ForEach(Remove);
}
}
and then your usage can be
public class User
{
public int? Id { get; set; }
public string Name { get; set; }
public DateTime Dob { get; set; }
}
public class Usage
{
private readonly ISession _session;
public Usage(ISession session) { _session = session; }
public void Create(User user)
{
_session.Add(user);
_session.Commit();
}
public void Update(User user)
{
var existing = _session.Single<User>(x => x.Id == user.Id);
// this gets cumbursome for an entity with many properties.
// I would use some thing like valueinjecter (nuget package)
// to inject the existing customer values into the one retreived from the Db.
existing.Name = user.Name;
existing.Dob = user.Dob;
_session.Commit();
}
}
I have deliberately not included a Repository class. To have a class encapsulate both queries and commands for every entity is an over kill and a needless abstraction. Its almost a design flaw at a fundamental level. Queries and commands are fundamentally different concerns. Queries in the most simplest manner can be created as extensions methods on the ISession interface. Commands can be done using a few classes like such..
public interface ICommand<in TSource>
{
void ApplyTo(TSource source);
}
public interface ICommandHandler<out TSource>
{
void Handle(ICommand<TSource> command);
}
public class LinqCommandHandler : ICommandHandler<IStore>
{
private readonly ISession _session;
public LinqCommandHandler(ISession session)
{
_session = session;
}
public void Handle(ICommand<IStore> command)
{
command.ApplyTo(_session);
_session.Commit();
}
}
public class UpdateDobForUserName : ICommand<IStore>
{
public string UserName { get; set; }
public DateTime Dob { get; set; }
public void OnSend(IStore store)
{
var existing = store.Query<User>().SingleOrDefault(x => x.Name == UserName);
existing.Dob = Dob;
}
}
public class Usage
{
private readonly ICommandHandler<IStore> _commandHandler;
public Usage(ICommandHandler<IStore> commandHandler)
{
_commandHandler = commandHandler;
}
public void Update()
{
var command = new UpdateDobForUserName {UserName = "mary", Dob = new DateTime(1960, 10, 2)};
_commandHandler.Handle(command);
}
}
The IStore above is the same as the Session class, except that it doesn't implement the IDisposable interface and doesn't have a Commit() method. The ISession then obviously inherits from an IStore and also implements IDisposable and has one method Commit(). This ensures an ICommand<IStore> can never open or dispose connections and cannot commit. Its responsibility is to define a command and define how its applied. Who applies it and what happens and what not on command application is a different responsibility which is with the ICommandHandler<IStore>.
There are many ways to implement Unit of work. I prefer having the repositories take a Unit of Work in its constructor (which is passed via Dependency Injection), then you only create repositories for your needs.
My question is very similar to this one: MVC3 tool using Entity Framework caching issues with Ninject however my mapping is a bit more complex and when I use InRequestScope I get the following error:
The operation cannot be completed because the DbContext has been disposed.
If I don't include InRequestScope everything works except EF Code First seems to cache my entities and it doesn't match up to the values in the Db.
Here's my ninject mapping I'm using the ninject mvc3 nuget package (without InRequestScope):
kernel.Bind<MyContext>()
.ToSelf()
.WithConstructorArgument("connectionString", context => MvcApplication.GetConnectionStringName);
kernel.Bind<IUnitOfWork>().To<UnitOfWork>();
// Service Layer.
kernel.Bind<ICustomerService>().To<CustomerService>();
kernel.Bind<IMessageService>().To<MessageService>();
kernel.Bind<IUserService>().To<UserService>();
// Repository Layer.
kernel.Bind<IRepository<Customer>>().To<GenericRepository<Customer>>();
kernel.Bind<IRepository<Message>>().To<GenericRepository<Message>>();
kernel.Bind<IRepository<User>>().To<GenericRepository<User>>();
NinjectContainer.Initialize(kernel);
My IUnitOfWork
public interface IUnitOfWork
{
IUserService UserService { get; }
ICustomerService CustomerService { get; }
IMessageService MessageService { get; }
void CommitChanges();
}
My UnitOfWork
public class UnitOfWork : IUnitOfWork
{
MyContext _context;
private readonly IUserService _userService;
private readonly ICustomerService _customerService;
private IMessageService _messageService;
public UnitOfWork(IUserService userService,
ICustomerService customerService,
IMessageService messageService,
MyContext context)
{
_userService = userService;
_customerService = customerService;
_messageService = messageService;
SetContext(optimaContext);
}
private void SetContext(MyContext context)
{
_context = context;
_userService.Context = _context;
_customerService.Context = _context;
_messageService.Context = _context;
}
public void CommitChanges()
{
_context.SaveChanges();
}
public IUserService UserService { get { return _userService; } }
public ICustomerService CustomerService { get { return _customerService; } }
public IMessageService MessageService { get { return _messageService; } }
}
My ICustomerService
public interface ICustomerService
{
DbContext Context { get; set; }
IQueryable<Customer> All();
}
My CustomerService
public class CustomerService : ICustomerService
{
IRepository<Customer> _customerRepo;
public CustomerService(IRepository<Customer> customerRepo)
{
_customerRepo = customerRepo;
}
private DbContext _context;
public DbContext Context
{
get { return _context; }
set { _context = value; _customerRepo.Context = value; }
}
public IQueryable<Customer> All()
{
return _customerRepo.All();
}
}
My other services follow a similar patter.
My IRepository
public interface IRepository<T> where T : class, new()
{
DbContext Context { get; set; }
T Single(Expression<Func<T, bool>> expression);
T Find(object id);
IQueryable<T> All();
void Delete(Expression<Func<T, bool>> expression);
void Delete(T item);
}
My Repository
public class GenericRepository<T> : IRepository<T> where T : class, new()
{
DbContext _context;
public DbContext Context
{
get { return _context; }
set { _context = value; }
}
public virtual T Single(Expression<Func<T, bool>> expression)
{
return All().FirstOrDefault(expression);
}
public virtual T Find(object id)
{
return _context.Set<T>().Find(id);
}
public virtual IQueryable<T> All()
{
return _context.Set<T>();
}
public virtual void Delete(Expression<Func<T, bool>> expression)
{
var items = All().Where(expression);
foreach (var item in items)
{
Delete(item);
}
}
public virtual void Delete(T item)
{
_context.Set<T>().Remove(item);
}
}
If anyone can help with the Ninject mapping and the correct way to inject classes it would be greatly appreciated.
I found the problem, I was using the [Inject] attribute with a FilterAttribute when the attribute was being called it was before my context had been initialised and that producted the dbContext error.
I followed the wiki on the ninject github site here to setup ninject on FilterAttribute. On issue I did have was finding the BindFilter method, this is hidden away Ninject.Web.Mvc.FilterBindingSyntax namespace.
My ninject mappings now look like:
kernel.Bind<MyContext>()
.ToSelf()
.InRequestScope()
.WithConstructorArgument("connectionString", context => MvcApplication.GetConnectionStringName);
kernel.Bind<IUnitOfWork>().To<UnitOfWork>();
// Service Layer.
kernel.Bind<ICustomerService>().To<CustomerService>();
kernel.Bind<IMessageService>().To<MessageService>();
kernel.Bind<IUserService>().To<UserService>();
// Repository Layer.
kernel.Bind<IRepository<Customer>>().To<GenericRepository<Customer>>();
kernel.Bind<IRepository<Message>>().To<GenericRepository<Message>>();
kernel.Bind<IRepository<User>>().To<GenericRepository<User>>();
// Attributes
kernel.BindFilter<AuthorizeWithTokenAttribute>(FilterScope.Controller, 0)
.WhenControllerHas<AuthorizeWithTokenFilter>()
.WithConstructorArgumentFromControllerAttribute<AuthorizeWithTokenFilter>("roles", attribute => attribute.Roles)
.WithConstructorArgumentFromControllerAttribute<AuthorizeWithTokenFilter>("users", attribute => attribute.Users);