I want to access some data within my overriden SaveChanges() in my dbcontext without passing any parameters. Any suggestions? I'm working with MVC4 and Entity Framework Database-First.
public partial class Entities : DbContext
{
public override int SaveChanges()
{
// i want to get user info from MVC model but no need to pass any parameters when call SaveChanges()
var UserInfo = userInfo;
// Call the original SaveChanges(), which will save both the changes made and the audit records
return base.SaveChanges();
}
}
Solution 1: Dependency Injection
This solution is pretty extensible, but you would have to modify the code in your repositories and controllers to use the injected dependencies instead of creating new instances with new.
Install Ninject. In Visual Studio, find the Package Manager Console and run Install-Package Ninject.MVC4 -dependencyVersion Highest in there.
Add constructor injection. Modify your controller, so that it gets an instance of your repository in its constructor. Modify your repository, so that it gets an instance of your entity context in its constructor. Cache your dependencies in private fields. Example code:
// In your controller:
public MyController(MyRepository repo)
{
this.repo = repo;
}
// In your repository:
public MyRepository(Entities context)
{
this.context = context;
}
// In your entities:
public Entities(UserInfo userInfo)
{
this.userInfo = userInfo;
}
Add a UserInfo provider. We need to tell Ninject where to get the UserInfo from. We can use the provider interface here:
public class UserInfoProvider : Provider<UserInfo>
{
protected override UserInfo CreateInstance(IContext context)
{
UserInfo UserInfo = new UserInfo();
// Do some complex initialization here.
return userInfo;
}
}
Add bindings. We need to tell Ninject to use the provider. We also want the lifetime of a UserInfo instance and of our entity context to be bound to the request cycle of MVC. Update your App_Start\NinjectWebCommon.cs:
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<Entities>()
.ToSelf()
.InRequestScope();
kernel.Bind<UserInfo>()
.ToProvider<UserInfoProvider>()
.InRequestScope();
}
Run your app. Ninject should use your constructors and provide the requested dependencies.
For further information, visit the Ninject Wiki.
Solution 2: Thread local context
This requires no modification to your repositories, but it makes the code less testable and resembles an anti pattern somehow. This won't work if your controller calls multithreaded code.
Add context class.
public class UserInfoContext : IDisposable
{
private static readonly ThreadLocal<UserInfo> UserInfos = new ThreadLocal<UserInfo>();
public static UserInfo Current
{
get
{
if (UserInfos == null)
{
throw new InvalidOperationException("UserInfoContext has not been set.");
}
return UserInfos.Value;
}
}
public static UserInfoContext Create(UserInfo userInfo)
{
if (userInfo == null)
{
throw new ArgumentNullException("userInfo");
}
if (UserInfos.Value != null)
{
throw new InvalidOperationException("UserInfoContext should not be nested.");
}
UserInfos.Value = userInfo;
return new UserInfoContext();
}
private UserInfoContext() { }
public void Dispose()
{
UserInfos.Value = null;
}
}
Wrap your controller code. Example:
public ActionResult Index()
{
using (UserInfoContext.Create(myUserInfo))
{
// do stuff that calls your repositories
return View();
}
}
Update your Entities class.
public partial class Entities : DbContext
{
public override int SaveChanges()
{
var UserInfo = UserInfoContext.Current;
// Call the original SaveChanges(), which will save both the changes made and the audit records
return base.SaveChanges();
}
}
Related
Working with EntityFramework and Ninject i need to dispose the context each time a call to a repository is finished. I need that so each time, a new call to the database is made, instead of using the EF context scope.
Here is my repository for testing:
public class VehicleRepositoryTest : IVehicleRepository
{
private DBEntities _context;
public VehicleRepositoryTest(DBEntities context)
{
_context = context;
}
....
public List<TB_VEHICULO> GetAll()
{
return _context.TB_VEHICULO.ToList();
}
And here is how i implement the ninject module. I use "IntransientScope" with the idea of disposing the context after each call:
Kernel.Bind<DBEntities>().ToSelf().InTransientScope();
Kernel.Bind<IVehicleRepository>().To<Test.VehicleRepositoryTest>().InTransientScope();
The idea is that each time a call "GetAll()" a new context is created, so each time a call to database is made.
But it is not working. If i make a call to "GetAll()", and supose i get data A; then i change in database data A to data B, make a new call to "GetAll()", i still getting data A.
More Info:
My application is a WinForms application, to call the instantiate the injected objects i use the composition pattern:
public static class CompositionRoot
{
public static IKernel kernel { get; private set; }
public static void WireModule(INinjectModule module)
{
kernel = new StandardKernel(module);
}
public static T Resolve<T>()
{
return kernel.Get<T>();
}
}
and the call to the repository is like this:
_vehicleRepository = CompositionRoot.Resolve<IVehicleRepository>();
var test = _vehicleRepository.GetAll();
I was with the same problem.
My old code:
kernel.Bind(typeof(IUnitOfWork)).To<UnitOfWork>().WithConstructorArgument("context", kernel.Get<MyContext>());
My new Code:
kernel.Bind<DbContext>().To<MyContext>();
kernel.Bind(typeof(IUnitOfWork)).To<UnitOfWork>();
This work to me.
I've been trying to implement a .net MVC Unit of Work API (rather than creating a separate repository), but it doesn't feel right. Am I going about this the correct way?
BaseController
public class BaseController : ApiController
{
protected DBEntities _dbEntities;
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
_dbEntities = new DBEntities();
}
protected override void OnActionExecuted(ActionExecutedContext filterContext)
{
_dbEntities.SaveChanges();
}
}
MyController
public class MyController : BaseController
{
public HttpResponseMessage PutMyObject(int id, int id2)
{
if (id != 0)
{
var myObject = _dbEntities.MyObjects.Where(x => x.id == id);
if (myObject.Count() > 0)
{
MyObject temp = myObject.SingleOrDefault();
temp.Processed = true;
return Request.CreateResponse(HttpStatusCode.OK);
}
else
{
return Request.CreateErrorResponse(HttpStatusCode.NotFound);
}
}
else
{
/* do some other stuff */
}
}
}
My thinking around this is that the controller action is a single Unit of Work. The database connection is opened when the controller action starts, and SaveChanges is called once the response is returned.
Am I going about this in the correct manner? do i need to dispose of _dbentities after savechanges is called within the BaseController? (or is this a better question for code review exchange)
I think, It would be a bad design for OOP architecture and flexibility. Because, you have to provide database actions in your main MVC project and you couldn't provide them in other layers. So, you should provide repository pattern and you should access the repositories from main MVC project and other required projects. So, I suggest you to handle _dbEntities object in a singleton class for per thread.
Sample singleton class would be like this;
public class UnitOfWorkSampleContextBase : IDisposable
{
[ThreadStatic]
private static UnitOfWorkSampleContextBase _instance;
public static UnitOfWorkSampleContextBase Instance
{
get
{
if (_instance == null)
{
_instance = new UnitOfWorkSampleContextBase();
}
return _instance;
}
}
public SampleDbContext Context { get; private set; }
private UnitOfWorkSampleContextBase()
{
}
public void Commit()
{
Context.SaveChanges();
}
public void ResolveContext()
{
Context = new SampleDbContext(ConfigurationManager.ConnectionStrings["MainDatabase"].ConnectionString);
}
public void Dispose()
{
Context.Dispose();
Context = null;
}
}
And you can create the DbContext like this;
UnitOfWorkSampleContextBase.Instance.ResolveContext();
Then, you can perform actions in context like this;
var context = UnitOfWorkSampleContextBase.Instance.Context;
var records = context.sampleEntities.ToList();
Finally, you can commit and dispose the context like this;
UnitOfWorkSampleContextBase.Instance.Commit();
UnitOfWorkSampleContextBase.Instance.Dispose();
The singleton class should be in repository or base layer to be accessed desired repository classes.
Note : If you are using CastleWindsor or something like that, creating
and commiting the context would be better in an interceptor. Also, it is very important that the singleton context class should be initialized for per thread.
I'm having two problems, the first is scaling and became visible while load testing.
Under load, things quickly (10 concurrent or less) fail with the error:
There is already an open DataReader associated with this Command which must be closed first.
Or
ExecuteReader requires an open and available Connection. The connection's current state is open.
The stack trace references a repository every time, example:
Line 23: public AboutViewDto GetAboutView()
Line 24: {
Line 25: var featured = UnitOfWork.FaqRepository
Line 26: .GetFeatured()
Original NinjectDependencyResolver:
public class NinjectDependencyResolver
: IDependencyResolver, System.Web.Mvc.IDependencyResolver
{
private readonly IKernel _kernel;
public NinjectDependencyResolver() : this(new StandardKernel())
{
}
public NinjectDependencyResolver(IKernel kernel)
{
_kernel = kernel;
AddBindings(_kernel);
}
public IDependencyScope BeginScope()
{
return this;
}
public object GetService(Type serviceType)
{
return _kernel.TryGet(serviceType);
}
public IEnumerable<object> GetServices(Type serviceType)
{
return _kernel.GetAll(serviceType);
}
public void Dispose()
{
// nothing??
}
private static void AddBindings(IBindingRoot kernel)
{
kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
kernel.Bind<IDataContext>().To<PublicCommentDbContext>().InSingletonScope();
kernel.Bind<IUnitOfWork>().To<UnitOfWork>().InSingletonScope();
kernel.Bind(typeof(IRepository<>)).To(typeof(Repository<>)).InSingletonScope();
kernel.Bind<IFaqRepository>().To<FaqRepository>().InSingletonScope();
kernel.Bind<IListValueRepository>().To<ListValueRepository>().InSingletonScope();
kernel.Bind<INoticeRepository>().To<NoticeRepository>().InSingletonScope();
kernel.Bind<IOrganizationRepository>().To<OrganizationRepository>().InSingletonScope();
kernel.Bind<ITagRepository>().To<TagRepository>().InSingletonScope();
kernel.Bind<IAdminService>().To<AdminService>();
kernel.Bind<IAutoMapperService>().To<AutoMapperService>();
kernel.Bind<IHomeService>().To<HomeService>();
kernel.Bind<IInfoService>().To<InfoService>();
kernel.Bind<IMailService>().To<MailService>();
kernel.Bind<INoticeService>().To<NoticeService>();
kernel.Bind<IOrganizationService>().To<OrganizationService>();
kernel.Bind<ISearchService>().To<SearchService>();
kernel.Bind<IValidator<QuestionDto>>().To<QuestionDtoValidator>();
kernel.Bind<IValidator<NoticeCommentDto>>().To<CommentDtoValidator>();
kernel.Bind<IValidator<NoticeContactDto>>().To<NoticeContactDtoValidator>();
kernel.Bind<IValidator<NoticeDto>>().To<NoticeDtoValidator>();
kernel.Bind<IValidator<OrganizationDto>>().To<OrganizationDtoValidator>();
}
}
}
I had a hunch that InSingletonScope() was causing the problem so I changed it to:
kernel.Bind<IDataContext>().To<PublicCommentDbContext>().InRequestScope();
And changed all of the other SingletonScopes to RequestScope.
After making that change, the site handles 400+ concurrent users without any failures, however...
Now no commits work against the database. I can trace the calls through the controller, to the service, to the repository, and to the DBContext commit, but the inserts or updates are not happening.
I'll post snippets of each item here in hopes someone can spot the dumb error we've made or suggest improvements.
Snippets follow:
Activity, update a Notice, everything involved:
1) Ninject:
kernel.Bind<IDataContext>().To<PublicCommentDbContext>().InRequestScope();
kernel.Bind<IUnitOfWork>().To<UnitOfWork>().InRequestScope();
kernel.Bind(typeof(IRepository<>)).To(typeof(Repository<>)).InRequestScope();
kernel.Bind<INoticeService>().To<NoticeService>();
.. etc...
2) Controller:
public sealed class NoticeController : BaseController
{
public NoticeController(IAutoMapperService autoMapperService, INoticeService noticeService)
{
AutoMapperService = autoMapperService;
NoticeService = noticeService;
}
...
3) NoticeService
public class NoticeService : BaseService, INoticeService
{
public NoticeService(
IUnitOfWork unitOfWork,
IAutoMapperService autoMapperService,
IValidator<NoticeDto> noticeDtoValidator)
: base(unitOfWork)
{
AutoMapperService = autoMapperService;
NoticeDtoValidator = noticeDtoValidator;
}
4) Unit of Work
public class UnitOfWork : IUnitOfWork
{
private IDataContext _dataContext;
private bool _disposed;
private ObjectContext _objectContext;
private DbTransaction _transaction;
public UnitOfWork(
IDataContext dataContext,
INoticeRepository noticeRepository)
{
_dataContext = dataContext;
NoticeRepository = noticeRepository;
}
5) Notice Repository
public class NoticeRepository : Repository<Notice>, INoticeRepository
{
public NoticeRepository(IDataContext context) : base(context)
{
}
...
6) Controller Action
public ActionResult Create(NoticeViewModel notice)
{
notice.TypeId = Convert.ToInt32(NoticeType.ManuallyEnteredDocument);
var newNotice = AutoMapperService.Map<NoticeViewModel, NoticeDto>(notice);
NoticeService.Create(newNotice);
return RedirectToAction("Details", new { name = notice.Arc });
}
7) NoticeService.Create(new):
public void Create(NoticeDto notice)
{
NoticeDtoValidator.ValidateAndThrow(notice);
var newNotice = AutoMapperService.Map<NoticeDto, Notice>(notice);
UnitOfWork.NoticeRepository.Add(newNotice);
UnitOfWork.SaveChanges();
}
8) Generic Repository Add():
public virtual void Add(TEntity entity)
{
entity.ObjectState = ObjectState.Added;
_dbSet.Attach(entity);
_context.SyncObjectState(entity);
}
9) UnitOfWork SaveChanges():
public int SaveChanges()
{
return _dataContext.SaveChanges();
}
When I step through this, the entity that is attached in #8 looks right, the status is added, when save changes is called there are no changes recorded in the base SaveChanges():
public override int SaveChanges()
{
SyncObjectsStatePreCommit();
base.ChangeTracker.DetectChanges();
var result = base.ChangeTracker.HasChanges();
var changes = base.SaveChanges();
result here is false
How could that be? What am I missing, other than abstraction hell and UoW/Repos on top of EF6 context, (I inherited this).
Someone out there see anything ELSE dumb?
No errors, no exceptions, the inserts just don't happen.
Problem solved, the issue was that Ninject was injecting a different context into our repositories.
We found two ways to solve this:
Option 1) In our unit of work we created an additional constructor that just receives a dbcontext and creates new repositories passing them the dbcontext. We left the old constructor as well so we can inject the repos for testing. This worked great and was a trivial change to make.
Option 2) Removed Ninject and overloaded the constructors for each Controller, manually creating the items. Since this project was small, we only had to touch 6 controllers and it worked fine, just 4 new lines of code in each. We left the old constructor as well so we can inject the services for testing.
I have a problem with EF5. I am using MVC 4.5
I am trying to make the 1 context per request "pattern".
I am not using "unit of work" pattern, nor testing or DI.
I am using the Generic Repository pattern to interact with DB. Each repository uses the same context mantained by a singleton "DataContextManager".
In each request in the global asax I refresh the context, but something wrong is happening: ie: I have a paged list and moving by the pages if i change data in DB manualy it doesnt refresh correctly. It's not an HTML cache issue, i tested it.
I know is a EF Context problem because i have "something like this":
private static Context C; //for the singleton. And in global.asax
public Application_BeginRequest()
{
DataContextManager.RefreshNew();
}
protected void Application_EndRequest(object sender, EventArgs e)
{
Domain.DataContextManager.Dispose();
}
And the first time the list works and in the second page i get an error saying that the
Context is disposed.
I read something of using the context in Static variables, but i don't know whats happening. I would like to use something simple like this, because to implement the UnitOfWork pattern i will need to change a lot of code.
Here is a little snnipet of my classes:
public class DataContextManager
{
private static Entities _Context;
private const string ConnectionString = "connString";
public static Entities Context
{
get
{
if (DataContextManager._Context == null)
DataContextManager._Context = new Entities(ConfigurationManager.ConnectionStrings[ConnectionString].ConnectionString);
return DataContextManager._Context;
}
}
//This method is not necessary but made it for testing
public static void RefreshNew()
{
DataContextManager._Context = new Entities(ConfigurationManager.ConnectionStrings[ConnectionString].ConnectionString);
}
public static void Dispose()
{
if (DataContextManager._Context != null)
{
DataContextManager._Context.Dispose();
DataContextManager._Context = null;
}
}
}
And repositories use DataContextManager like this:
public class BaseRepository<TEntity> where TEntity : class
{
internal Entities context;
internal DbSet<TEntity> dbSet;
public BaseRepository()
: this(DataContextManager.Context)
{
}
public BaseRepository(Entities context)
{
this.context = context;
this.dbSet = context.Set<TEntity>();
}
Thanks in advance!
Pablo.
I don't know that you really need the manager class, since everything seems to just access the DbContext property.
That being said, you should normally avoid using DbContext in a static class; I don't have any canonical source to back that up, but my personal experience has been that it at some point causes more problems than any benefit having a static class provides. So, I'd update the manager like so:
public class DataContextManager
{
private readonly string connectionToUse = string.Empty;
private Entities _context;
public Entities Context
{
get
{
if (_context == null)
{
_context = new Entities(WebConfigurationManager.ConnectionStrings[connectionToUse].ConnectionString);
}
return _context;
}
}
public DataContextManager()
{
connectionToUse = "connString";
}
public DataContextManager(string key)
{
connectionToUse = key;
}
#region IDisposable Members
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposeAll)
{
if (disposeAll)
{
_context.Dispose();
}
_context = null;
}
#endregion
}
Then you simply add a protected field to each of your controllers and instantiate the manager in the controller's constructor:
protected DataContextManager Manager = null;
public HomeController()
{
Manager = new DataContextManager();
// or
//
//__manager = new DataContextManager("connection-To-Use");
}
If all of your controllers use the same DbContext class, you could create a BaseController class that inherits System.Web.Mvc.Controller and move the manager into it, which saves some duplication.
I currently been assigned to a asp mvc project using entity framework. This will be a Line of Business application. I want to develop this app using repository and unit of work pattern. I'm new to this pattern (and new to .net too) and i am having a problem in understanding the pattern and how to implement it.
I have read numerous articles and i think this is how my application should be
Entity Framework -> Repository -> Unit of Work -> Client (Asp MVC)
I attach some code from this article
http://www.asp.net/mvc/tutorials/getting-started-with-ef-using-mvc/implementing-the-repository-and-unit-of-work-patterns-in-an-asp-net-mvc-application
using System;
using ContosoUniversity.Models;
namespace ContosoUniversity.DAL
{
public class UnitOfWork : IDisposable
{
private SchoolContext context = new SchoolContext();
private GenericRepository<Department> departmentRepository;
private GenericRepository<Course> courseRepository;
public GenericRepository<Department> DepartmentRepository
{
get
{
if (this.departmentRepository == null)
{
this.departmentRepository = new GenericRepository<Department>(context);
}
return departmentRepository;
}
}
public GenericRepository<Course> CourseRepository
{
get
{
if (this.courseRepository == null)
{
this.courseRepository = new GenericRepository<Course>(context);
}
return courseRepository;
}
}
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);
}
}
}
Unit of Work will have repositories and will create DBContext upon creation
So controller will create Unit of Work upon creation.
To Show data i will use this code
var department = UoW.departmentRepository.Find(1);
return View(department);
and when client click save button, i will run this code
UoW.departmentRepository.Update(department);
UoW.Save();
My question:
What if it takes hours from data retrieval until the client click save button. From what i know, we have to keep context as short as possible.
Where should i put business logic? Do i put it in repository? So i would call UoW.departmentRepository.Validate(department) before save. But then, what if i need to validate entity which relate to other entity. Do i call UoW.departmentRepository.Validate(course, department)?
Is there a complete sample project for this kind of application?
EDIT
As Ant P adviced, i need to add another layer to put my business logic.
This is what i have come so far
Unit Of Work:
public class UnitOfWork : IDisposable
{
private DBContext _context = new DBContext();
public DBContext Context
{
get
{
return this._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);
}
}
Business Logic:
public class SalesBusinessLogic : IDisposable
{
private ICustomerRepository _customerRepo;
private ISalesRepository _salesRepo;
private UnitOfWork _uow;
public SalesBusinessLogic(UnitOfWork uow)
{
this._uow = uow;
}
public ICustomerRepository CustomerRepo
{
get
{
if (this._customerRepo == null)
{
this._customerRepo = new CustomerRepository(this._uow);
}
return this._customerRepo;
}
}
public ISalesRepository SalesRepo
{
get
{
if (this._salesRepo == null)
{
this._salesRepo = new SalesRepository(this._uow);
}
return this._salesRepo;
}
}
public bool Validate(Sales sales)
{
//this is where validation performed
return true;
}
}
Controller:
public SalesController : Controller
{
private UnitOfWork _uow = new UnitOfWork();
private SalesBusinessLogic _bl = new SalesBusinessLogic(this._uow);
public ActionResult Index()
{
var sales = _bl.SalesRepo.Find(1);
sales.CustomerID = 1;
if _bl.Validate(sales)
{
_bl.SalesRepo.Update(sales);
_uow.Save();
}
return View(sales);
}
}
Here UnitOfWork act only as provider of dbcontext, which will be consumed by business logic and repository.
Repository will be in BusinessLogic class.
Server side validation will be handled by BusinessLogic and client side validation will be handled by viewmodel in Web Layer.
My only concern is that dbcontext in UnitofWork is publicly accessible.
Am i in the right direction here?
What if it takes hours from data retrieval until the client click save button. From what i know, we have to keep context as short as possible.
This isn't an issue - the controller is instantiated per request. It doesn't persist while the user views the page. It sounds like you're misunderstanding at what point the controller is instantiated. When you instantiate the UnitOfWork within the controller's constructor, the process flow goes like this:
The user issues a POST request (by clicking 'Save').
The request reaches the server and the controller is instantiated (thereby instantiating the unit of work).
The action method is called.
The unit of work is disposed.
Where should i put business logic? Do i put it in repository? So i would call UoW.departmentRepository.Validate(department) before save. But then, what if i need to validate entity which relate to other entity. Do i call UoW.departmentRepository.Validate(course, department)?
Typically, your business logic would be abstracted into a separate layer that sits between your web application and your repositories. Tutorials that show you repositories injected directly into controllers assume that you have "thin" business logic.
However, validation definitely isn't the job of a repository. You should create a separate view model for each view and validate those in your controller. The repository should be used pretty much solely for CRUD operations.