Using LINQ-to-SQL containers - asp.net-mvc-3

I'm using MVC3 and currently i'm following a practice such that I declare one instance of DB Container for every controller. I use that container instance for every request coming to that controller. If I need to go to my models for a query or sth, I send that instance as a parameter to the model's function. So for the whole application, I create and use 4-5 different instances of DB Container class. My question is, does this have a good or bad effect on my database operations? Does it matter to create a seperate container instance? What is the proper way to use container classes?
I believe the mentioned class was called DBContext before.

I am not sure it is what you mean but I can give you an example of an approach I'm following rather often:
Create a sort of 'domainservice class' for the DBContext
public class MyDomainService : IDisposable
{
private MyDbEntities dbo;
private bool isDisposed;
public MyDomainService()
{
dbo = new MyDbEntities();
}
public User GetUser(string userName)
{
return (from usr in dbo.Users
where usr.UserName == userName
select usr).SingleOrDefault();
}
public void Dispose()
{
if (isDisposed)
return;
isDisposed = true;
dbo.Dispose();
}
}
Create a custom Controller class that extends Controller or AsyncController
and override the Initialize and Dispose methods:
public class MyController : Controller
{
protected MyDomainService DomainService { get; private set; }
protected override void Initialize(System.Web.Routing.RequestContext
requestContext)
{
base.Initialize(requestContext);
DomainService = new MyDomainService();
}
protected override void Dispose(bool disposing)
{
DomainService.Dispose();
base.Dispose(disposing);
}
}
Now you can use the following approach in per example the HomeController inheriting MyController
public class HomeController : MyController
{
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult Index(string username)
{
var user = DomainService.GetUser(username);
if (user != null)
return RedirectToAction("Account", "Information");
return View();
}
}
This will keep your controllers rather clean.

Related

Access TempData in ExecuteResult Asp.Net MVC Core

I wanted to save notification in TempData and shown to user. I create extension methods for this and implement a class which Extends from ActionResult. I need to access TempData in override ExecuteResult method with ActionContext.
Extension Method:
public static IActionResult WithSuccess(this ActionResult result, string message)
{
return new AlertDecoratorResult(result, "alert-success", message);
}
Extends ActionResult class.
public class AlertDecoratorResult : ActionResult
{
public ActionResult InnerResult { get; set; }
public string AlertClass { get; set; }
public string Message { get; set; }
public AlertDecoratorResult(ActionResult innerResult, string alertClass, string message)
{
InnerResult = innerResult;
AlertClass = alertClass;
Message = message;
}
public override void ExecuteResult(ActionContext context)
{
ITempDataDictionary tempData = context.HttpContext.RequestServices.GetService(typeof(ITempDataDictionary)) as ITempDataDictionary;
var alerts = tempData.GetAlert();
alerts.Add(new Alert(AlertClass, Message));
InnerResult.ExecuteResult(context);
}
}
Call extension method from controller
return RedirectToAction("Index").WithSuccess("Category Created!");
I get 'TempData ' null , How can I access 'TempData' in 'ExecuteResult' method.
I was literally trying to do the exact same thing today (have we seen the same Pluralsight course? ;-) ) and your question led me to find how to access the TempData (thanks!).
When debugging I found that my override on ExecuteResult was never called, which led me to try the new async version instead. And that worked!
What you need to do is override ExecuteResultAsync instead:
public override async Task ExecuteResultAsync(ActionContext context)
{
ITempDataDictionaryFactory factory = context.HttpContext.RequestServices.GetService(typeof(ITempDataDictionaryFactory)) as ITempDataDictionaryFactory;
ITempDataDictionary tempData = factory.GetTempData(context.HttpContext);
var alerts = tempData.GetAlert();
alerts.Add(new Alert(AlertClass, Message));
await InnerResult.ExecuteResultAsync(context);
}
However, I have not fully understood why the async method is called as the controller is not async... Need to do some reading on that...
I find out the way to get the TempData. It need to get from ITempDataDictionaryFactory
var factory = context.HttpContext.RequestServices.GetService(typeof(ITempDataDictionaryFactory)) as ITempDataDictionaryFactory;
var tempData = factory.GetTempData(context.HttpContext);

Repository Parameter in controller asp.net mvc

I try to learn repository.I created a class below,
public class Repository<T> where T : class
{
ObjectContext _context;
IObjectSet<T> _objectSet;
DBEntities db = new DBEntities ();
public void Delete(T entity)
{
_objectSet.DeleteObject(entity);
_context.SaveChanges();
}
}
}
I try to use void Delete in my controller below,
public ActionResult Index()
{
var something = new Repository<Department>();
something.Delete(.......); // What i must add to delete method ? How can i delete data from database ?
return View();
}
If i write int value to "something.Delete(2); it does not work, i do not know what to add here,how can i use repository ?
Try this article here:
The Repository Pattern Example in C#
MSDN ObjectContext.DeleteObject Method

Passing multiple models to a view using MVC3 and Ninject

I'm new to MVC3 (which is why I bought a book on it, which is why I now have this question!), so apologies if there is an obvious answer to this!
I'm following a simple example of building a shopping cart in MVC3. The book advocates the use of Ninject for dependency injection, which I'm also new to. It all seems straight forward enough with one model, in this case Product, but building upon this I am struggling to add a second model and display this in the same view where the Product model is displayed. I've tried using a View Model but all examples I find wrap several classes into one model and I can't quite figure out how to implement this in my code.
The class:
public class Product
{
public int ProductId {get;set;}
public string Name {get;set;}
}
Abstract Repository:
public interface IProductRepository
{
IQueryable<Product> Products {get;}
}
Class to associate model with database:
public class EFDbContext : DbContext
{
public DbSet<Product> Products {get;set;}
}
Product Repository which implements abstract interface:
public class EFProductRepository : IProductRepository
{
private EFDbContext context = new EFDbContext();
public IQueryable<Product> Products
{
get {return context.Products;}
}
}
Ninject binds IProductRepository to EFProductRepository in a ControllerFactory class.
Controller:
public class ProductController : Controller
{
private IProductRepository repository;
public ProductController(IProductRepository productRepository)
{
repository = productRepository;
}
public ViewResult List()
{
return View(repository.Products);
}
}
My problem is passing repository.Products to the strongly typed view; if I need to pass another entity, which is very feasible how would I achieve this???
You can build a ViewModel which looks like the following:
public class YourViewModel
{
public List<Product> Products { get; set; }
public List<OtherEntity> OtherEntities { get; set; }
}
Then you can wrap the repository in a service which contains all the methods
you need to fulfill your requests and/or businesslogic:
public class YourService
{
private IProductRepository repository;
public List<Product> GetAllProducts( )
{
return this.repository.Products.ToList( );
}
public List<OtherEntity> GetAllOtherEntites( )
{
return this.repository.OtherEntites.ToList( );
}
}
and finally in the Controller you fill the ViewModel appropriately
public class ProductController : Controller
{
private YourControllerService service = new YourControllerService( );
// you can make also an IService interface like you did with
// the repository
public ProductController(YourControllerService yourService)
{
service = yourService;
}
public ViewResult List()
{
var viewModel = new YourViewModel( );
viewModel.Products = service.GetAllProducts( );
viewModel.OtherEntities = service.GetAllOtherEntities( );
return View( viewModel );
}
}
Now you have multiple entities on you ViewModel.
Maybe it is not directly answer to your question but it is connected.
If you correctly pass the model to view, you can handle it like this
#model SolutionName.WebUI.Models.YourViewModel
#Model.Product[index].ProductId
#Model.OtherEntity[index].OtherId
I know that it's old post but it maybe help others :)

ObjectContext not retrieving recent changes

This code works fine, However, if I run execute a storedprocedure in my unit of work class (or any update, delete, add operation), I'm still getting original the data. Actually, I have already a solution(posted below in controller) but Im sure this is not the most elegant way, I hope someone can help me refactor the code. please help. Thanks
My unit of work
public class UnitOfWork : IUnitOfWork, IDisposable
{
private readonly ObjectContext _context;
private BookRepository _books;
public UnitOfWork(ObjectContext context)
{
if (context == null)
{
throw new ArgumentNullException("Context was not supplied");
}
_context = context;
}
public IRepository<Book> Books
{
get
{
if (_books== null)
{
_books= new BookRepository (_context);
}
return _books;
}
}
public void UpdateAuthor(int id)
{
_context.ExecuteStoreCommand("sp_UpdateAuthor #param1",
new SqlParameter("param1", id));
}
public void Commit()
{
_context.SaveChanges();
}
Book Repository
public class BookRepository : Repository<Book>
{
public BookRepository (ObjectContext context)
: base(context)
{
}
public override Machine GetById(object id)
{
return _objectSet.SingleOrDefault(s => s.Id== (int)id);
}
}
Generic Repository
public abstract class Repository<T> : IRepository<T>
where T : class, IAuditEntity
{
protected IObjectSet<T> _objectSet;
public Repository(ObjectContext context)
{
_objectSet = context.CreateObjectSet<T>();
}
public abstract T GetById(object id);
public IEnumerable<T> GetAll()
{
return _objectSet;
}
public IEnumerable<T> Query(Expression<Func<T, bool>> filter)
{
return _objectSet.Where(filter);
}
public void Add(T entity)
{
_objectSet.AddObject(entity);
}
public void Remove(T entity)
{
_objectSet.DeleteObject(entity);
}
}
Controller Code
public class HomeController : Controller
{
private IUnitOfWork _unitOfWork;
#region Core Action Methods
public HomeController()
{
this._unitOfWork = new UnitOfWork(((IObjectContextAdapter)new BookContext()).ObjectContext);
}
private IEnumerable<BookViewModel> GetBookdsViewModels(int id)
{
//THE CODE WHERE ITS NOT RETURNING THE UPDATED VLAUES
//var query = _unitOfWork.Books.GetAll().Where(d => d.Id== id);
//I WANT TO CHANGE THIS CODE
ObjectContext objectContext = ((IObjectContextAdapter)new BookContext()).ObjectContext;
ObjectSet<Book> set = objectContext.CreateObjectSet<Book>();
set.MergeOption = MergeOption.OverwriteChanges;
var query = from a in set
where a.Id== id && !a.IsDeleted
select a;
return query
.Select(
c => new BookViewModel
{
Id = c.Id ,
Name = c.Name
});
}
I believe the problem is because you're executing things directly against your database, and then trying to refer back to the local copy that's stored in your repository and they're different.
public void UpdateAuthor(int id)
{
_context.ExecuteStoreCommand("sp_UpdateAuthor #param1",
new SqlParameter("param1", id));
}
When you run this query, you're making a change in your db instead of your local - why dont you do something like this:
public void UpdateAuthor(int id)
{
var book = Books.GetById(id);
/* make changes to your book object */
_unit.Save();
}
If you're wanting to make changes using store procs, you're going to have to dispose of your context, and recreate the repo's so that you're working with data from the DB instead of the local copy.
Expanding on Mark Oreta's answer, you need to ensure your Model is updated after manually executing a stored proc on your database. If you must manually call that stored proc then try this afterward:
_context.Entry<Book>(instanceOfAuthor).Reload();
Which might be:
_context.Entry<Book>(_context.Books.GetById(id)).Reload();

Custom Membership + Ninject + InRequestScope = ObjectContext instance has been disposed

ObjectContext instance has been disposed in InRequestScope!
I tried for several hours across the web to try to solve a problem.
The ObjectContext instance has been disposed and can no longer be used
for operations that require a connection.
I found several articles and posts with the same problem like this, this, this and this
I tried all ways, but always an error occurs.
Code
Context
public class BindSolutionContext : DbContext
{
public DbSet<Project> Projects { get; set; }
public DbSet<User> Users { get; set; }
public DbSet<Role> Roles { get; set; }
public DbSet<Address> Addresses { get; set; }
public DbSet<ProjectImage> ProjectImages { get; set; }
public BindSolutionContext()
: base("name=Data")
{
Database.SetInitializer(new DropCreateDatabaseIfModelChanges<BindSolutionContext>());
}
}
Ninject
kernel.Bind<BindSolutionContext>().ToSelf().InRequestScope();
kernel.Bind<IProjectRepository>().To<ProjectRepository>().InRequestScope();
kernel.Bind<IUserRepository>().To<UserRepository>().InRequestScope();
kernel.Bind<IRoleRepository>().To<RoleRepository>().InRequestScope();
kernel.Bind<IAddressRepository>().To<AddressRepository>().InRequestScope();
kernel.Bind<IProjectImageRepository>().To<ProjectImageRepository>().InRequestScope();
Repository
public class ProjectRepository : IProjectRepository
{
private readonly BindSolutionContext _context;
public ProjectRepository(BindSolutionContext context)
{
_context = context;
}
public IQueryable<Project> Query(params Expression<Func<Project, object>>[] includeProperties)
{
return includeProperties.Aggregate<Expression<Func<Project, object>>,
IQueryable<Project>>(_context.Projects, (current, includeProperty) => current.Include(includeProperty));
}
public IQueryable<Project> Query(int pageIndex, int pageSize, params Expression<Func<Project, object>>[] includeProperties)
{
return includeProperties.Aggregate<Expression<Func<Project, object>>,
IQueryable<Project>>(_context.Projects, (current, includeProperty) => current.Include(includeProperty)).OrderBy(p => p.Name).Skip(pageIndex).Take(pageSize);
}
//Rest of Implementation
}
For ProjectImageRepository, AddressRepository, RoleRepository and UserRepository implementation follows the same model!
public class BindUserProvider : MembershipProvider
{
[Inject]
public IUserService UserService { get; set; }
//Rest of implementation
}
public class BindRoleProvider : RoleProvider
{
private IRoleService _roleServ;
private IRoleService RoleServ { get { return _roleServ ?? (_roleServ = DependencyResolver.Current.GetService<IRoleService>()); } }
private IUserService _userServ;
private IUserService UserServ { get { return _userServ ?? (_userServ = DependencyResolver.Current.GetService<IUserService>()); } }
//Rest of implementation
}
As the scope is request, the Ninject should dispose of object at then end of the request. But in some situations, dispose occurs before finalizing the request.
Attempts
I'm not sure if the problem is related to the Custom membership, but did some testing. follows:
Ninject
kernel.Bind<BindSolutionContext>().ToSelf().InTransientScope();
kernel.Bind<IProjectRepository>().To<ProjectRepository>().InSingletonScope();
kernel.Bind<IUserRepository>().To<UserRepository>().InSingletonScope();
kernel.Bind<IRoleRepository>().To<RoleRepository>().InSingletonScope();
kernel.Bind<IAddressRepository>().To<AddressRepository>().InSingletonScope();
kernel.Bind<IProjectImageRepository>().To<ProjectImageRepository>().InSingletonScope();
So there is no more error!
But another problem arises! As the repository and context are singleton objects are not updated.
For example, if I register a new address for the project, the collection project.Addresses is not updated !
Note: The address is registered in the database without any problems!
Membership and RoleProviders have a longer lifecycle than a request. Objects should never depend on shorter lived objects (unless locally created and destroyed during a method execution) because they would end up referencing disposed objects.
Since you want a new context foreach request to avoid having cached objects you must not inject the context into the repositories but pass it from outside with the method call and either create it in the services or the providers using a factory.
To avoid this exception, use DependencyResolver.Current.GetService() instead of injected properties in classes that have long life cycle (action filters, membership providers etc.). This approach is not test friendly, but it lets you access a data context instance of the current http-request when you use InRequestScope().
I removed dependency injection and did it this way...
public class CustomRoleProvider:RoleProvider
{
private IGroupService _groupService;
private MyDbContext context;
public CustomRoleProvider()
{
// _groupService = DependencyResolver.Current.GetService<IGroupService>();
context = new MyDbContext();
_groupService = new GroupService(new GroupRepository(context), new AccountRepository(context));
}
}

Resources