I trying to implement business layer (service layer) along with repository layer. So my project has following layers EF <--- Repository <--- Service <--- Controller <--- View.
My context class looks like :
public class ToDoContext : DbContext
{
public ToDoContext()
: base("ToDoContext")
{
}
public virtual DbSet<Project> Projects { get; set; }
public virtual DbSet <Collaborator> Collaborators { get; set; }
public virtual DbSet<ActionTask> Tasks { get; set; }
}
My ProjectRepository looks like :
public class ProjectRepository : IProjectRepository, IDisposable
{
ToDoContext Context;
public ProjectRepository(ToDoContext context)
{
this.Context = context;
}
public virtual List<Project> AllProjects()
{
IQueryable<Project> projects = Context.Projects;
return projects.ToList<Project>();
}
public Project Find(int? id)
{
// some code
}
public void InsertOrUpdate(Project project)
{
// some code
}
public void Delete(int? id)
{
// some code
}
public void Save()
{
// some code
}
public void Dispose()
{
Context.Dispose();
}
}
My ProjectService class looks like :
public class ProjectService : IProjectService
{
IProjectRepository ProjectRepo;
ICollaboratorRepository CollaboratorRepo;
public ProjectService(IProjectRepository projectRepo, ICollaboratorRepository collaboratorRepo)
{
this.ProjectRepo = projectRepo;
this.CollaboratorRepo = collaboratorRepo;
}
public List<Project> GetAllProjects()
{
return ProjectRepo.AllProjects();
}
public void CreateProject(FormCollection formData)
{
// code to parse form data as per my business needs
// code to code to fetch related collaborator list
// save the project data
}
public List<Collaborator> GetCollaborators(string[] collaboratorId)
{
// Fetch collaborator list using collaborator repository
return CollaboratorRepository.GetAllCollaborators();
}
}
Similarly I have implemented service and repository layer for my collaborator.
To summarize the code my CreateProject() method in ProjectService class fetches collaborator list using collaborator repository and create a new project attaching the collaborator list with this newly created project and save it.So i guess for me this whole process is One Unit Of Work.
When I fetch list of collaborators using CollaboratorRepository and try to save the newly created project using ProjectRepository, it throws me error "An entity object cannot be referenced by multiple instances of IEntityChangeTracker.". I guess this is because CollaboratorRepository dbcontext is not disposed yet. So I am manually disposing each context before using new context. I know I can't afford this overhead of manually disposing the context. Can anyone help me please?
I know I should be using same dbcontext object for one unit of work. But i don't know how to achieve this when dbcontext object is exposed to repository rather than service layer.
How is the IoC configured? You should register the LifeTime of the DbContext per Request\Thread, in order to get the same instance per business transaction.
Tips: In order to have a reusable Service outside of a web enviroment, do not pass the FormCollection to the CreateProject method. The parsing of the FormCollection should be done by the controller\model binder.
For Ninject, try InRequestScope
kernel.Bind<ToDoContext>().To<ToDoContext>().InRequestScope();
Related
I am struggling with wiring dependencies through autofac in my WebApi 2 project. I have a following interface and class that i'd like to inject in my GET and POST controller actions,
public interface IRepository
{
IContext Context
{
get;
}
void SomeOperation();
}
public MyRepository : IRepository
{
IContext _context;
public MyRepository(IContext context)
{
_context = context;
}
public Context
{
get
{
return _context;
}
}
public void SomeOperation
{
// Perform some operation using _context;
}
}
I 'd like IRepository to be injected in controller like this,
public class MyController : ApiController
{
private readonly IRepository _repo;
public ApplicationsController(IRepository repo)
{
_repo = repo;
}
// GET: api/v1/Contexts({contextId})
public IHttpActionResult Get(string contextId)
{
_repo.SomeOperation();
}
}
IContext object to be injected in MyRepository has to be fetched from a factory, something like this
public class ContextFactory
{
Hashtable contextMap;
IContext Get(string contextId)
{
if contextMap.Contains(contextId)
return contextMap[contextId].Value;
else
{
IContextConfiguration configuration = ContextConfigurationFactory.Get(contextId);
IContext context = new ConcreteContext(configuration);
contextMap.Add[contextId, context];
return context;
}
}
}
I am not sure how to wire all the classes and convert logic in factory classes by injecting relationships through Autofac so that context id passed in url is passed to ContextConfigurationFactory.Get and instantiate ConcreteContext object when not found in hash and eventually Autofac injecting right context object in MyRepository before passing it on to Get action in the controller.
Let's simplify this a bit. What you're trying to do is:
Get the context ID from a route parameter.
Use that route parameter in the factory to create a context.
The rest seems pretty much peripheral - the repository, the controller, all that. The crux of the question is that you need to get a route parameter into your factory.
Given that, let's put together some simplified code:
public class ContextFactory
{
public IContext Get(string contextId)
{
return new Context(contextId);
}
}
public interface IContext
{
string Id { get; }
}
public class Context : IContext
{
public Context(string id)
{
this.Id = id;
}
public string Id { get; private set; }
}
That's basically what you have:
An IContext interface that things need.
A ContextFactory that is basically responsible for building these things.
A Context concrete implementation of IContext that is built by the factory.
I would probably do something like this:
var builder = new ContainerBuilder();
builder.RegisterType<ContextFactory>();
builder.Register(ctx =>
{
var routeData = HttpContext.Current.Request.RequestContext.RouteData;
var id = routeData.Values["contextId"] as string;
var factory = ctx.Resolve<ContextFactory>();
return factory.Get(id);
}).As<IContext>()
.InstancePerLifetimeScope();
Now when you resolve IContext it will use your factory, get the current context ID from route data, and pass it through the factory.
I will leave the following for you to look into:
What happens if the route parameter isn't there? (Autofac won't let you return null.)
What happens if the route parameter has invalid data?
The route parameter is pretty hackable, is this a security risk?
...and so on.
Does anyone know how we can inject context into User Manager > MongoDB serStore at runtime in .net core 2.0.
We cannot do this at startup due to the context being dynamic but the UserStore is not accessible and UserManager has too many variables to new up, and it is wrong. Are there any solutions?
public class UserStore<TUser> :
IUserPasswordStore<TUser>,
IUserRoleStore<TUser>,
IUserLoginStore<TUser>,
IUserSecurityStampStore<TUser>,
IUserEmailStore<TUser>,
IUserClaimStore<TUser>,
IUserPhoneNumberStore<TUser>,
IUserTwoFactorStore<TUser>,
IUserLockoutStore<TUser>,
IQueryableUserStore<TUser>,
IUserAuthenticationTokenStore<TUser>
where TUser : IdentityUser
{
private readonly IMongoCollection<TUser> _Users;
//THIS IS WHERE WE WANT TO INJECT THE users AT RUNTIME
public UserStore(IMongoCollection<TUser> users)
{
_Users = users;
}
public virtual void Dispose()
{
// no need to dispose of anything, mongodb handles connection pooling automatically
}
public virtual async Task<IdentityResult> CreateAsync(TUser user, CancellationToken token)
{
await _Users.InsertOneAsync(user, cancellationToken: token);
return IdentityResult.Success;
}
unfortunately users is null at startup, and should be as the tenant has not been created at that point.
We have also been using the saaskit.Multitenancy and just can't find a solution.
Any help would be much appreciated.
Thanks
i think u need a generic repository to act as a wrapper for IMongoCollection then inject the repository inside controllers
public class Repository<T>
{
public IMongoCollection<T> Collection { get; private set; }
public Repository(IDbFactory dbFactory)
{
MongoClient client = new MongoClient("ur connection string");
this.Collection = client.GetDatabase("db").GetCollection<T>(typeof(T).Name);
}
public T Find(Expression<Func<T, bool>> filter)
{
return this.Collection.AsQueryable<T>().FirstOrDefault<T>(filter);
}
public async Task<T> FindAsync(Expression<Func<T, bool>> filter)
{
return await this.Collection.AsQueryable<T>().FirstOrDefaultAsync<T>(filter);
}
// here add more methods
}
then register the dependency as below inside Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddTransient(typeof(IRepository<>), typeof(Repository<>));
services.AddMvc();
}
finally inside controllers u inject the generic repository, also dont forget to Implement the IDisopsible in genereic repository
public class ProductController : Controller
{
private readonly IRepository<Product> _productRepository = null;
public ProductController(IRepository<Product> productRepository)
{
this._productRepository = productRepository;
}
}
I am building an EntityFramework/WebApi back end.
I want to decouple my WebApi from the Entity Framework, and utilize Dependency Injection so I can swap out the "data source" for the web API.
I have been looking at the Unit of Work and Repository patterns.
I also want to use breezejs.
The breezejs TempHire samples has been alot of help, so I will use this as an example for my question -
https://github.com/Breeze/breeze.js.samples/tree/master/net/TempHire
In this sample, on the data side we have the UnitOfWork class -
public class UnitOfWork
{
private readonly EFContextProvider<TempHireDbContext> _contextProvider;
public UnitOfWork()
{
_contextProvider = new EFContextProvider<TempHireDbContext>();
StaffingResources = new Repository<StaffingResource>(_contextProvider.Context);
Addresses = new Repository<Address>(_contextProvider.Context);
// .. etc.
}
public IRepository<StaffingResource> StaffingResources { get; private set; }
public IRepository<Address> Addresses { get; private set; }
// .. etc.
public SaveResult Commit(JObject changeSet)
{
return _contextProvider.SaveChanges(changeSet);
}
}
Then on the WebApi side, it uses it like this -
[BreezeController]
[Authorize]
public class ResourceMgtController : ApiController
{
private readonly UnitOfWork _unitOfWork = new UnitOfWork();
[HttpPost]
public SaveResult SaveChanges(JObject saveBundle)
{
return _unitOfWork.Commit(saveBundle);
}
// ... etc.
}
I would like to refactor to something like this, so that I could swap out the back end.
public class UnitOfWork : IUnitOfWork
public class ResourceMgtController : ApiController
{
private readonly IUnitOfWork _unitOfWork;
public ResourceMgtController(IUnitOfWork unitOfWork) {
this._unitOfWOrk = unitOfWork; // Dependency Injected...
}
// ... etc.
}
What I can't wrap my head around, is how I can make it generic. The breeze client needs a method like this -
[HttpPost]
public SaveResult SaveChanges(JObject saveBundle)
{
return _unitOfWork.Commit(saveBundle);
}
And I can't put this in IUnitOfWork -
SaveResult SaveChanges(JObject saveBundle)
And really keep it decoupled from breeze, be able to swap out the back end for another backend. Am I attempting the abstraction at the wrong point? I guess if I want breeze on the client I will need to couple it on the backend?
You clearly can define an interface with that method:
public interface IUnitOfWork {
...
SaveResult SaveChanges(JObject saveBundle); // no problem
}
I suspect that you are objecting to the fact that both SaveResult and JObject are classes defined by libraries (Breeze.ContextProvider and Newtonsoft.Json.Linq respectively) you'd rather not reference somewhere.
These references wouldn't bother me any more than I mind referencing System.Linq to get IQueryable. In fact, a test double of SaveResult (a public class of Breeze.ContextProvider) is trivially easy to construct. Here is its definition (and the definition of KeyMapping, its only non-native dependent type):
public class SaveResult
{
public List<object> Entities;
public List<KeyMapping> KeyMappings;
public List<object> Errors;
}
public class KeyMapping
{
public string EntityTypeName;
public object TempValue;
public object RealValue;
}
But if Breeze and Newtonsoft.Json references are that noxious to you and you're willing to surrender some type safety, you can always create the interface like this:
public interface IUnitOfWork {
...
object SaveChanges(object saveBundle); // no safety, no problem
}
Then in your concrete UnitOfWork you add a suitable overload:
public object IUnitOfWork.SaveChanges(object saveBundle)
{
return SaveChanges((JObject) saveBundle);
}
public SaveResult SaveChanges(JObject saveBundle)
{
return _contextProvider.SaveChanges(saveBundle);
}
... and Bob's your uncle.
Yes, I did try it (in DocCode); worked fine for me.
I have an MVC app (EF6, SQL Server CE 4), that I recently refactored to add a UnitOfWork class and a service layer (so that I could utilise a single DbContext per request, and conduct transactions successfully).
Previously, I was using Unity to inject the repositories into the controller. My unit tests (for the controllers) were simple to setup - I just mocked each repository, and passed those into the controller constructor.
After refactoring, I now use Unity to inject the Service Layer (to the controller) and UnitOfWork (into the Service Layer). The Service Layer now instantiates each repository, by passing the UnitOfWork.DbContext to the repository's constructor.
In my Unit Tests, I am attempting to mock the UnitOfWork, and the ServiceLayer (and pass the mocked UnitOfWork object into the ServiceLayer's constructor). However, the tests fail, saying "TestFixtureSetup failed in ControllerTest".
I assume it's due to how I'm attempting to pass the UnitOfWork mock into the ServiceLayer mock, so would appreciate any guidance on how to do this correctly.
Relevant code snippets below.
UnitOfWork
public interface IUnitOfWork:IDisposable
{
void Save();
IDSMContext Context { get; }
}
public class UnitOfWork : IUnitOfWork, IDisposable
{
private IDSMContext _context;
public UnitOfWork()
{
_context = new IDSMContext();
}
public IDSMContext Context
{
get {return _context;}
}
public void Save()
{
_context.SaveChanges();
}
private bool disposed = false;
protected virtual void Dispose(bool disposing)
{
if (!this.disposed)
{
if (disposing)
{
_context.Dispose();
}
}
this.disposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
Service Layer
public interface IService
{
// Repositories
IUserRepository Users { get; }
IUserTeamRepository UserTeams { get; }
IPlayerRepository Players { get; }
IGameRepository Games { get; }
IUserTeam_PlayerRepository UserTeamPlayers { get; }
void Save();
}
public class Service: IService, IDisposable
{
private IUnitOfWork _unitOfWork;
private IUserRepository _userRepository;
private IUserTeamRepository _userTeamRepository;
private IPlayerRepository _playerRepository;
private IGameRepository _gameRepository;
private IUserTeam_PlayerRepository _userTeamPlayerRepository;
public Service(IUnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;
initialiseRepos();
}
private void initialiseRepos(){
_userRepository = _userRepository ?? new UserRepository(_unitOfWork.Context);
_userTeamRepository = _userTeamRepository ?? new UserTeamRepository(_unitOfWork.Context);
_playerRepository = _playerRepository ?? new PlayerRepository(_unitOfWork.Context);
_gameRepository = _gameRepository ?? new GameRepository(_unitOfWork.Context);
_userTeamPlayerRepository = _userTeamPlayerRepository ?? new UserTeam_PlayerRepository(_unitOfWork.Context);
}
public IUserRepository Users { get { return _userRepository; } }
public IUserTeamRepository UserTeams { get { return _userTeamRepository; } }
public IPlayerRepository Players { get { return _playerRepository; } }
public IGameRepository Games { get { return _gameRepository; } }
public IUserTeam_PlayerRepository UserTeamPlayers { get { return _userTeamPlayerRepository; } }
public void Save()
{
_unitOfWork.Save();
}
Unity Container Instance Setup
Instance.RegisterType<IService, Service>(new PerThreadLifetimeManager())
.RegisterType<IUnitOfWork, UnitOfWork>();
Controller Constructor
public GameController(IService service)
{
_service = service;
}
Test Constructor
_mockUnitOfWork = new Mock<IUnitOfWork>();
_mockServiceLayer = new Mock<IService>(_mockUnitOfWork.Object); //this line fails
Test Controller Method
GameController Controller = new GameController(_mockServiceLayer.Object);
If you want to test methods of GameController you just need to mock/stub the dependencies of that class. Just do this:
_mockServiceLayer = new Mock<IService>();
_controller = new GameController(_mockServiceLayer.Object);
When you are testing the Controller, you shouldn't worry about the dependencies of the service. UnitOfWork is never exposed outside your service, so don't worry about it when testing the controller. On your tests you may now setup expectations of methods called on your service, like verifying that Save was called once (If you were testing the service, then you would worry about the IService.Save calling Save on a mock of the IUnitOfWork!):
_mockServiceLayer.Verify(s=> s.Save(), Times.Once());
The problem you will find is that your service class is not abstracting the controller from the repositories, as your controller will get the repositories via the properties in IService and query directly the repositories. So if you want to test your controller methods, you will still need to mock the repositories, doing something like:
//Initialization before each test:
_mockUserRepo = new Mock<IUserRepository>();
//...other repositories
_mockServiceLayer = new Mock<IService>();
_mockServiceLayer.Setup(s => s.Users).Returns(_mockUserRepo.Object);
//... setup properties in IService for other repositories
_controller = new GameController(_mockServiceLayer.Object);
//In some test:
var user = new User();
_mockUserRepo.Setup(s => s.Get(123)).Returns(user);
call some controller method and make sure returned model is "user"
This way you may find yourself configuring the expectations and data returned by a few repositories and the UnityOfWork, just for testing the methods in the Controller! Not to mention that your Controller class effectively depends on your repositories, not just on the service.
Another approach would be if your service class contains higher level methods like GetUser, CreateUser or AddUserToTeam (likely having multiple services with closely related methods). The service would then shield the controller from retrieving/sending data to the repositories and using the UnitOfWork.
That way in your tests you would only need to mock IService.
For example a test for a typical "GET" action may look like:
//Arrange
var user = new User();
_mockServiceLayer.Setup(s => s.GetUser(123)).Returns(user);
//Act
var viewResult = _controller.GetUser(123) as ViewResult;
//Assert
Assert.AreEqual(user, viewResult.Model);
Hopefully this will help clarifying things a bit!
In the line that fails you are mocking the IService which does not have a constructor, so passing it args will cause it to fail. Since you are only trying to unit test the controller, you should change the line to this:
_mockServiceLayer = new Mock<IService>();
and then specify the the behaviors you want using _mockServiceLayer.Setup(...). Remember your interface doesn't know anything about your unit of work so you do not need to mock the unit of work.
If you actually want to test the controller and service layer together then you would do something like this:
_mockUnitOfWork = new Mock<IUnitOfWork>();
var serviceLayer = new Service(_mockUnitOfWork.Object);
var controller = new GameController(serviceLayer);
You would probably be better off unit testing the controllers and the serviceLayer separately, each time mocking the layer below.
I am creating an ASP.NET MVC 3 e-commerce website and I am currently working on the admin area where you can add/edit products. To create the UI for the product page I am using Telerik MVC controls.
My problem is that when I added a second telerik grid which both retrieve data from the database through an ajax call I receive a couple different errors listed below:
{"There is already an open DataReader associated with this Command
which must be closed first."}
{"The connection was not closed. The connection's current state is
connecting."}
Database Context Code
public interface IUnitOfWork
{
void Commit();
}
public class GSPDataContext : DbContext, IUnitOfWork
{
/* (omitted) IDbSet's for entities */
public GSPDataContext()
: base("GSPConnectionString")
{
}
public virtual IDbSet<T> DbSet<T>() where T : class
{
return Set<T>();
}
public virtual void Commit()
{
base.SaveChanges();
}
}
Generic Repository Code
public class Repository<T> : IRepository<T> where T : class
{
private GSPDataContext m_dataContext;
private readonly IDbSet<T> m_entity;
public Repository(GSPDataContext dataContext)
{
if (dataContext == null)
throw new ArgumentException();
m_dataContext = dataContext;
m_entity = m_dataContext.Set<T>();
}
public T GetById(int id)
{
return this.m_entity.Find(id);
}
public void Insert(T entity)
{
if (entity == null)
throw new ArgumentException();
this.m_entity.Add(entity);
//this.m_dataContext.SaveChanges();
}
public void Delete(T entity)
{
if (entity == null)
throw new ArgumentException();
this.m_entity.Remove(entity);
//this.m_dataContext.SaveChanges();
}
public virtual IQueryable<T> Table
{
get
{
return this.m_entity;
}
}
}
Ninject Code
private static void RegisterServices(IKernel kernel)
{
//Customer
kernel.Bind<IAddressValidationService>().To<AddressValidationService>().InRequestScope();
kernel.Bind<ICustomerService>().To<CustomerService>().InRequestScope();
kernel.Bind<ICustomerProductService>().To<CustomerProductService>().InRequestScope();
//Authentication
kernel.Bind<IOpenIDLoginService>().To<OpenIDLoginService>().InRequestScope();
kernel.Bind<IAuthenticationService>().To<FormsAuthenticationService>().InRequestScope();
//Products
kernel.Bind<IProductService>().To<ProductService>().InRequestScope();
kernel.Bind<IRecentlyViewedProductService>().To<RecentlyViewedProductService>().InRequestScope();
kernel.Bind<IProductPictureService>().To<ProductPictureService>().InRequestScope();
kernel.Bind<ICategoryService>().To<CategoryService>().InRequestScope();
kernel.Bind<IPictureService>().To<PictureService>().InRequestScope();
//Shopping Cart
kernel.Bind<IShoppingCartService>().To<ShoppingCartService>().InRequestScope();
//Shipping and Payment
kernel.Bind<IShippingService>().To<ShippingService>().InRequestScope();
kernel.Bind<IPaymentService>().To<PaymentService>().InRequestScope();
//Orders
kernel.Bind<IOrderCalculationService>().To<OrderCalculationService>().InRequestScope();
kernel.Bind<IOrderProcessingService>().To<OrderProcessingService>().InRequestScope();
kernel.Bind<IOrderService>().To<OrderService>().InRequestScope();
//
kernel.Bind<IEncryptionService>().To<EncryptionService>().InRequestScope();
kernel.Bind<ILogger>().To<LoggingService>().InRequestScope();
kernel.Bind<IWebManager>().To<WebManager>().InRequestScope();
//Messages
kernel.Bind<IEmailService>().To<EmailService>().InRequestScope();
kernel.Bind<IMessageTemplateService>().To<MessageTemplateService>().InRequestScope();
kernel.Bind<IWorkflowMessageService>().To<WorkflowMessageService>().InRequestScope();
//Data
kernel.Bind<GSPDataContext>().ToSelf().InSingletonScope();
kernel.Bind<IUnitOfWork>().ToMethod(ctx => ctx.Kernel.Get<GSPDataContext>()).InSingletonScope();
kernel.Bind(typeof (IRepository<>)).To(typeof (Repository<>)).InRequestScope();
kernel.Bind<IWorkContext>().To<WebWorkContext>().InRequestScope();
}
I suspect it has something to do with how ninject is managing the lifetimes of the various services, but I am not sure what I need to do to make it work.
Any advice would be much appreciated.
Thanks
UPDATE
According to Remo's comment I change my code to the following:
//Data
kernel.Bind<GSPDataContext>().ToSelf().InRequestScope();
kernel.Bind<IUnitOfWork>().ToMethod(ctx => ctx.Kernel.Get<GSPDataContext>()).InRequestScope();
kernel.Bind(typeof (IRepository<>)).To(typeof (Repository<>)).InRequestScope();
And I am now getting the following error:
The ObjectContext instance has been disposed and can no longer be used
for operations that require a connection.
Any ideas?
No, it has nothing to do with how Ninject manages lifetimes. But it has to do how you configured the lifecycles.
It is important that a new DbContext is used for each request. This has to be InRequestScope.