Dependecy Injection works with Unity but doesn't with Ninject - entity-framework

I've been working on EF Repository pattern with Unit of Work and DI. I was following this example: link In example is used Unity as DI container, but I want to use Ninject.
(Note: with Unity everything works just fine).
So I've set up my Ninject Controller Factory like this: link.
When i go to my controller and try to list messages, it works fine but when i try to create message nothing happens, values are passed to controller and to repository, but data isn't saved to database for some reason.
Here is controller constructor:
private readonly IUserRepository _userRepository;
private readonly IMessageThreadRepository _messageThreadRepository;
public TetsController(IMessageThreadRepository messageThreadRepository, IUserRepository userRepository)
{
_messageThreadRepository = messageThreadRepository;
_userRepository = userRepository;
}
And here is code for messageThreadRepository which is being called by controller
public class MessageThreadRepository : RepositoryBase<MessageThread>, IMessageThreadRepository
{
private readonly RepositoryBase<MessageThread> _messageThreadRepository;
private readonly RepositoryBase<Message> _messageRepository;
private readonly IUnitOfWork _unitOfWork;
private readonly UserRepository _userRepository;
public MessageThreadRepository(IUnitOfWork unitOfWork, RepositoryBase<MessageThread> messageThreadRepository,
IDatabaseContextFactory databaseContextFactory, UserRepository userRepository, RepositoryBase<Message> messageRepository)
: base(databaseContextFactory)
{
_unitOfWork = unitOfWork;
_messageThreadRepository = messageThreadRepository;
_userRepository = userRepository;
_messageRepository = messageRepository;
}
//some code here
// part with adding to database
Message message = messageFactory.CreateMessage(messageBody, userSender, messageThread);
_messageRepository.Add(message);
if (!doesThreadExist)
{
_messageThreadRepository.Add(messageThread);
}
_unitOfWork.Commit();
}
EDIT
I've tried to add User to database, but with no luck. Again I manage to fetch all users but I can't add them, here is User repository:
public class UserRepository : RepositoryBase<User>, IUserRepository
{
private readonly IUnitOfWork _unitOfWork;
private readonly RepositoryBase<User> _repository;
public UserRepository(IUnitOfWork unitOfWork, IDatabaseContextFactory databaseContextFactory, RepositoryBase<User> repository) : base (databaseContextFactory)
{
_unitOfWork = unitOfWork;
_repository = repository;
}
public User GetUserById(int id)
{
return _repository.GetSingleByCriteria(u => u.UserId.Equals(id));
}
public User GetUserByEmail(string email)
{
return _repository.GetSingleByCriteria(u => u.Email.Equals(email));
}
public User GetUserByUserName(string name)
{
return _repository.GetSingleByCriteria(u => u.UserName.Equals(name));
}
public void AddUser(User user)
{
_repository.Add(user);
_unitOfWork.Commit();
}
public IEnumerable<User> GetAllUsers()
{
return _repository.GetAll();
}
}

I assume you're using MVC since you reference an article about using it with MVC.
Did you do all the steps mentioned here?
http://bubblogging.wordpress.com/2012/06/04/mvc-controller-factory-ninject/
Why are you using a custom controller factory instead of using the built-in dependency injection support of MVC, using Ninject.MVC3 package?

Related

Inheriting logging services from base class

I have a .Net Core 3.1 API controller with a constructor that looks like this:
public class MachineListsController : ControllerBase
{
private readonly jiWeb_ProdContext _context;
private readonly ILogger _logger;
private readonly ILoggingMessageService _loggingMessage;
public MachineListsController(jiWeb_ProdContext context, ILogger<MachineListsController> logger, ILoggingMessageService loggingMessage)
{
_context = context;
_logger = logger;
_loggingMessage = loggingMessage;
}
public string Message { get; set; }
...
}
You can see that I am injecting a .Net Core logging service and the database context into it.
Then I use the logging like this in my controller methods:
[HttpGet("FactoryMachines/{factoryId}")]
public async Task<ActionResult<IEnumerable<MachineList>>> GetMachinesForFactory(Guid factoryId)
{
var machineList = await _context.MachineList.Where(n => n.FactoryId == factoryId).ToListAsync();
Message = _loggingMessage.GetLogSuccess(this.GetType().Name.ToString(), ControllerActions.GetAction, "FactoryMachines", factoryId.ToString());
_logger.LogInformation(Message);
return machineList;
}
The logging is working great, but I'm realizing that I should create a base class that handles logging so I don't have to add or change it inside of every controller I write.
So I started to write this base controller:
[ApiController]
public class MyBaseController : ControllerBase
{
readonly jiWeb_ProdContext _context;
readonly ILogger _logger;
readonly ILoggingMessageService _loggingMessage;
public BaseController(jiWeb_ProdContext context, ILogger<BaseController> logger, ILoggingMessageService loggingMessage)
{
_context = context;
_logger = logger;
_loggingMessage = loggingMessage;
}
}
Then I changed my controller to inherit from it like this:
public class MachineListsController : MyBaseController
{
[HttpGet("FactoryMachines/{factoryId}")]
public async Task<ActionResult<IEnumerable<MachineList>>> GetMachinesForFactory(Guid factoryId)
{
var machineList = await _context.MachineList.Where(n => n.FactoryId == factoryId).ToListAsync();
return machineList;
}
}
But I'm getting error and I'm unsure of what to do on the next step.
Here's the error:
There is no argument given that corresponds to the required formal parameter 'context' of 'BaseController.BaseController(jiWeb_ProdContext, ILogger<BaseController>, ILoggingMessageService)'
Specifically, how do I set up my controllers so that they can just use the base class for logging so I don't have to write logging code for every new controller action I create?
Thanks!
As far as I know, if the base class constructor method contains value, we should pass it in the subclass constructor method and also you should follow Nkosi comment to modify the property to protected.
More details, you could refer to below codes:
[ApiController]
public class MyBaseController : ControllerBase
{
protected readonly ILogger _logger;
public MyBaseController(ILogger<MyBaseController> logger)
{
_logger = logger;
}
}
[Route("api/[controller]")]
public class MachineListsController : MyBaseController
{
public MachineListsController(ILogger<MyBaseController> logger) :base(logger)
{
}
[HttpGet]
public IActionResult Get() {
_logger.Log(Microsoft.Extensions.Logging.LogLevel.Trace,"aaa" );
return Ok();
}
}
I am wondering, would there be a way to do the logging in the base class? Like where you call _logger.Log in the MachineListsController class, could that be moved to base?
As far as I know, we could only add logs before the MachineListsController's action executed or after the MachineListsController's action executed.
If this match your requirement, you could try to use action filter.
You could add iactionfilter interface to the basecontroller and overried the OnActionExecuted and OnActionExecuting method.
More details, you could refer to below codes:
[Route("api/[controller]")]
[ApiController]
public class MyBaseController : ControllerBase, IActionFilter
{
protected readonly ILogger _logger;
public MyBaseController(ILogger<MyBaseController> logger)
{
_logger = logger;
}
public void OnActionExecuted(ActionExecutedContext context)
{
_logger.Log(Microsoft.Extensions.Logging.LogLevel.Trace, "aaa");
int i = 0;
}
public void OnActionExecuting(ActionExecutingContext context)
{
_logger.Log(Microsoft.Extensions.Logging.LogLevel.Trace, "bbb");
int i = 0;
}
}
Result:

Passing connection string to Entity framework at runt time for each call

My Entity framework context is as following
public partial class MyContext : DbContext, IMyContext
{
static MyContext()
{
System.Data.Entity.Database.SetInitializer<MyContext>(null);
}
public MyContext()
: base("Name=MyContext")
{
}
I am resolving it through autofac in the following way
builder.RegisterType(typeof(MainContext)).As(typeof(DbContext)).InstancePerLifetimeScope();
builder.RegisterType<MainContext>().As<IMainContext>().InstancePerRequest();
This db context gets called in repository layer
#region Fields
private readonly IMyContext _context;
#endregion
#region Constructors and Destructors
public EmployeeRepository(IMyContext context)
{
_context = context;
}
#endregion
public void Create(Employee emp)
{
this._context.Employee.Add(emp);
}
Now my issue is , I want to set the connection string dynamically per call. The connection string will be passed through a webapi which i want to pass on to this context. Can anyone help me how can i do that? I am confused about autofac here. Secondly how can i make sure each call sets connection string and does not cache it.
You can use a factory that will build the context and set the connectionstring for you.
public interface IContextFactory
{
IContext GetInstance();
}
public class MyContextFactory : IContextFactory
{
public IContext GetInstance()
{
String connectionString = this.GetConnectionString(HttpContext.Current);
return new MyContext(connectionString);
}
private String GetConnectionString(HttpContext context)
{
// do what you want
}
}
builder.RegisterType<MyContextFactory>()
.As<IContextFactory>()
.InstancePerRequest();
builder.Register(c => c.Resolve<IContextFactory>().GetInstance())
.As<IContext>()
.InstancePerRequest();
If you can't get connectionstring based on HttpContext, you can change contextFactory implementation to expect initialization by WebAPI before creating the instance. For example :
public interface IContextFactory
{
IContext GetInstance();
void Initialize(String connectionString);
}
public class MyContextFactory : IContextFactory
{
private String _connectionString;
public void Initialize(String connectionString)
{
this._connectionString = connectionString;
}
public IContext GetInstance()
{
if (this._connectionString == null)
{
throw new Exception("connectionString not initialized");
}
return new MyContext(this._connectionString);
}
}
At the beginning of your web API call (through attribute for example), you can call the Initialize method. Because the factory is InstancePerRequest you will have one instance for the duration of the request.
By the way, I'm not sure to understand this registration
builder.RegisterType(typeof(MainContext)).As(typeof(DbContext)).InstancePerLifetimeScope();
builder.RegisterType<MainContext>().As<IMainContext>().InstancePerRequest();
It looks buggy because you will have 2 different registration of the same type and not for the same scope, is it intended ? Furthermore, it doesn't sound a good idea to register a DbContext, do you need this registration ?
The following registration looks better :
builder.RegisterType<MainContext>()
.As<IMainContext>()
.As<DbContext>()
.InstancePerRequest();

What's DataService Best practice using Entity Framework and Repository and UnitOfWork Patterns

I'm using EF and MVVM pattern. My question is about the Data Access Layer. in DAL I have the following classes:
MyObjectContext which is technically the standard ObjectContext now, but some Unit-of-work methods will be added to it later.
Repository<TModel> which handles the most needed queries (such as Add, GetAll, ...) on different ObjectSets.
A bunch of DataServices which make use of repositories to provide a higher level of data access for Core.
The project I'm working on is a business application with about 100 EntitySets so far, and there are times when a single interaction of a user can involve up to 20 different EntitySets (updating most of them). I currently add .Include(params string[]) to my queries to prevent ObjectContextDisposedException but it doesn't seem to be a reliable solution.
The question is should I create an instance of MyObjectContext (and therefore Repository) in each of DataService methods (like the following codes, it seems to me that the ability of Unit of work would be useless in this case) or should I create it outside of DataService and pass it to the DataServices through their constructors (or directly to each of the DataService methods) to handle a bunch of database actions (different tables and queries) together. And how?
Here's what MyObjectContext looks like:
public class MyObjectContext : ObjectContext, IUnitOfWork
{
public MyObjectContext()
: base("name=EdmContainer", "EdmContainer")
{
ContextOptions.LazyLoadingEnabled = true;
}
#region IUnitOfWork Members
public void Commit()
{
SaveChanges();
}
#endregion
}
This is how Repository looks like:
public class Repository<TModel>
{
private readonly SoheilEdmContext _context;
public Repository(IUnitOfWork unitOfWork)
{
if (unitOfWork == null)
throw new ArgumentNullException("unitOfWork");
_context = unitOfWork as SoheilEdmContext;
}
public TModel FirstOrDefault(Expression<Func<TModel, bool>> where)
{
return _context.CreateObjectSet<TModel>().FirstOrDefault(where);
}
public void Add(TModel entity)
{
_context.CreateObjectSet<TModel>().AddObject(entity);
}
...
}
And this is how a common DataService looks like:
public class JobDataService : IDataService<Job>
{
#region IDataService<Job> Members
public Job GetSingle(int id)
{
Job model = null;
using (var context = new MyObjectContext())
{
var repos = new Repository<Job>(context);
model = repos.FirstOrDefault(x => x.Id == id);
}
return model;
}
public IEnumerable<Job> GetAll()
{
using (var context = new MyObjectContext())
{
var repos = new Repository<Job>(context);
var models = repos.GetAll();
return models;
}
}
public IEnumerable<Job> GetActives()
{
throw new NotImplementedException();
}
public int AddModel(Job model)
{
using (var context = new MyObjectContext())
{
var repos = new Repository<Job>(context);
repos.Add(model);
context.SaveChanges();
}
}
public void UpdateModel(Job model)
{
throw new NotImplementedException();
}
public void DeleteModel(Job model)
{
using (var context = new MyObjectContext())
{
var repos = new Repository<Job>(context);
var model = repos.FirstOrDefault(x => x.Id == model.Id);
if (model == null) return;
repos.Delete(model);
context.SaveChanges();
}
}
#endregion
}
Any kind of idea or insight would be appreciated.
You can create an instance of MyObjectContext in each service, like JobDataService, however, it makes your code messy and it is hard to maintain. Create instance of MyObjectContext outside of DataService is better. What you have now, if you have 100 EntitySets, you have to create 100 DataServices. That is because the use of "Repository Pattern" and "UnitOfWork" here is not efficient. I would suggest doing the following:
ObjectContext
public class MyObjectContext : ObjectContext
{
public MyObjectContext() : base("name=EdmContainer", "EdmContainer")
{
ContextOptions.LazyLoadingEnabled = true;
}
#region IUnitOfWork Members
public void Commit()
{
SaveChanges();
}
#endregion
}
Generic Repository
public interface IRepository<TModel> where TModel : class
{
void Add(TModel entity);
IEnumerable<TModel> GetAll();
// Do some more implement
}
public class Repository<TModel> : IRepository<TModel> where TModel : class
{
private readonly ObjectContext _context;
public Repository(ObjectContext context)
{
_context = context;
}
public virtual void Add(TModel entity)
{
_context.CreateObjectSet<TModel>().AddObject(entity);
}
public virtual IEnumerable<TModel> GetAll()
{
return _context.CreateObjectSet<TModel>();
}
}
UnitOfWork
public interface IUnitOfWork : IDisposable
{
IRepository<Job> Jobs { get; }
IRepository<User> Users { get;}
void Commit();
}
public class UnitOfWork : IUnitOfWork
{
private readonly SoheilEdmContext _context;
private readonly IRepository<Job> _jobRepository;
private readonly IRepository<User> _userRepository;
public UnitOfWork(SoheilEdmContext context)
{
_context = context;
_jobRepository = new Repository<Job>(_context);
_userRepository = new Repository<User>(_context);
}
public IRepository<Job> Jobs{get { return _jobRepository; }}
public IRepository<User> Users{get { return _userRepository; }}
public void Commit(){_context.Commit();}
public void Dispose()
{
if (_context != null)
{
_context.Dispose();
}
GC.SuppressFinalize(this);
}
JodDataSerivce
public interface IDataService
{
IEnumerable<Job> GetAll();
}
public class DataService : IDataService
{
private readonly IUnitOfWork _unitOfWork;
public DataService(IUnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;
}
public IEnumerable<Job> GetAll()
{
return _unitOfWork.Jobs.GetAll();
}
}
Here I used interface for implementing everything, if you want to do the same, you need to use IoC Container. I used the "Simple Injector", you can find it here:
Simple Injector
One more suggestion, if you feel like you have too many I/O operations to implement, like database access, querying data, etc., you should consider using Asynchronous. Below is a good video on Asynchronous.
How to Build ASP.NET Web Applications Using Async

Entity Framework using Repository Pattern, Unit of Work and Unity

Using a combination provided from this example and this implementation I am trying to create a solution that decouples the UnitOfWork class from the individual repositories, as they violate the Open-Closed Principle, since every time you added a new repository you would have to modify the UnitOfWork class. I am using Unity as the IoC container to wire up dependencies.
The problem I have is that in automatically wiring up the UnitOfWork, IDbContext and the repositories (IEmployeeRepository and ICustomerRepository) using Unity, the repositories will be injected with separate instances of the UnitOfWork, which, of course, defeats the purpose. I need to share the context across the repositories, and it seems I am missing a piece to this puzzle - at the moment (see Service layer) the UnitOfWork instantiated will be different to the UnitOfWork for each of repositories.
How do inject the IUnitOfWork into the service layer and pass this instantiated shared UnitOfWork class to the respective repositories, using Unity and dependency injection?
Here's my proposed (fabricated) solution:
Repositories
public interface IRepository<TEntity> where TEntity : class
{
TEntity Create();
// omitted for brevity
}
public class Repository<TEntity> : IRepository<TEntity>
where TEntity : class
{
private readonly DbContext _context;
public Repository(IUnitOfWork uow)
{
_context = uow.Context;
}
public virtual TEntity Create(TEntity entity)
{
return _context.Set<TEntity>().Add(entity);
}
// omitted for brevity
}
public interface IEmployeeRepository : IRepository<Employee>
{
}
public interface ICustomerRepository : IRepository<Customer>
{
}
public class EmployeeRepository : Repository<Employee>
{
public EmployeeRepository(IUnitOfWork uow)
: base(uow)
{
}
}
public class CustomerRepository : Repository<Customer>
{
public CustomerRepository(IUnitOfWork uow)
: base(uow)
{
}
}
DbContext Factory
public interface IDbContextFactory
{
DbContext GetContext();
}
public class DbContextFactory : IDbContextFactory
{
private readonly DbContext _context;
public DbContextFactory()
{
_context = new MyDbContext("ConnectionStringName");
}
public DbContext GetContext()
{
return _context;
}
}
Unit Of Work
public interface IUnitOfWork
{
void SaveChanges();
DbContext Context { get; }
}
public class UnitOfWork : IUnitOfWork, IDisposable
{
private readonly DbContext _context;
private bool disposed = false;
public UnitOfWork(IDbContextFactory contextFactory)
{
_context = contextFactory.GetContext();
}
public void SaveChanges()
{
if (_context != null)
{
_context.SaveChanges();
}
}
public DbContext Context
{
get { return _context; }
}
protected virtual void Dispose(bool disposing)
{
if (!disposed)
{
if (disposing)
{
_context.Dispose();
}
}
disposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
Service
public class CompanyService
{
private readonly IUnitOfWork _uow;
private readonly IEmployeeRepository _employeeRepository;
private readonly ICustomerRepository _customerRepository;
public CompanyService(IUnitOfWork uow, IEmployeeRepository employeeRepository, ICustomerRepository customerRepository)
{
_uow = uow;
_employeeRepository = employeeRepository;
_customerRepository = customerRepository;
}
// over-simplified example method
public void AddEmployeeAndCustomer()
{
_employeeRepository.Create(new Employee {Id = 1, Name = "Test Employee"});
_customerRepository.Create(new Customer { Id = 2, Name = "Test Customer" });
_uow.SaveChanges();
}
}
I think what you are looking for is a per request lifetime manager so that you only get one UnitOfWork instance and one DbContext instance for the duration of a request. Unity 3 has the Unity bootstrapper for ASP.NET MVC which has a PerRequestLifetimeManager which lets you do this.
If you are not using ASP.NET then you could probably use a PerResolveLifetimeManager. Another approach I've seen is a HierarchicalLifetimeManager combined with a child container (which makes the registrations a singleton within the child container).

Injecting DbContext into Repository class library

The projects in my solution are set up like this:
App.Data
App.Models
App.Web
In App.Data, I'm using Entity Framework to access my data with a bunch of Repositories to abstract interaction with it. For obvious reasons, I would like my App.Web to reference only the App.Data project and not Entity Framework.
I'm using Constructor Injection to give my Controllers a reference to a Repository container that looks like this:
public interface IDataRepository
{
IUserRepository User { get; set; }
IProductRepository Product { get; set; }
// ...
}
public class DataRepository : IDataRepository
{
private readonly AppContext _context;
public DataRepository(AppContext context)
{
_context = context;
}
// ...
}
DataRepository will have a AppContext object (which inherits from Entity Framework's DbContext) that all the child Repositories will use to access the database.
So finally we come to my problem: how do I use Constructor Injection on DataRepository considering it's a code library and has no entry-point? I can't bootstrap AppContext in App.Web because then I have to reference Entity Framework from that project.
Or am I just doing something stupid?
You can define a RepositoryConnection class in App.Data that acts as a wrapper to the Context and removes the need to reference EF in App.Web. If you are using an IoC Container you can control the lifetime of the RepositoryConnection class to ensure that all instances of Repository get the same Context. This is a simplified example ...
public class RepositoryConnection
{
private readonly AppContext _context;
public RepositoryConnection()
{
_context = new AppContext();
}
public AppContext AppContext { get { return _context; } }
}
public class DataRepository : IDataRepository
{
private readonly AppContext _context;
public DataRepository(RepositoryConnection connection)
{
_context = connection.AppContext;
}
// ...
}