Caching Data Objects when using Repository/Service Pattern and MVC - asp.net-mvc

I have an MVC-based site, which is using a Repository/Service pattern for data access.
The Services are written to be using in a majority of applications (console, winform, and web). Currently, the controllers communicate directly to the services. This has limited the ability to apply proper caching.
I see my options as the following:
Write a wrapper for the web app, which implements the IWhatEverService which does caching.
Apply caching in each controller by cache the ViewData for each Action.
Don't worry about data caching and just implement OutputCaching for each Action.
I can see the pros and cons of each. What is/should the best practice be for caching with Repository/Service

Steve Smith did two great blog posts which demonstrate how to use his CachedRepository pattern to achieve the result you're looking for.
Introducing the CachedRepository Pattern
Building a CachedRepository via Strategy Pattern
In these two posts he shows you how to set up this pattern and also explains why it is useful. By using this pattern you get caching without your existing code seeing any of the caching logic. Essentially you use the cached repository as if it were any other repository.
public class CachedAlbumRepository : IAlbumRepository
{
private readonly IAlbumRepository _albumRepository;
public CachedAlbumRepository(IAlbumRepository albumRepository)
{
_albumRepository = albumRepository;
}
private static readonly object CacheLockObject = new object();
public IEnumerable<Album> GetTopSellingAlbums(int count)
{
Debug.Print("CachedAlbumRepository:GetTopSellingAlbums");
string cacheKey = "TopSellingAlbums-" + count;
var result = HttpRuntime.Cache[cacheKey] as List<Album>;
if (result == null)
{
lock (CacheLockObject)
{
result = HttpRuntime.Cache[cacheKey] as List<Album>;
if (result == null)
{
result = _albumRepository.GetTopSellingAlbums(count).ToList();
HttpRuntime.Cache.Insert(cacheKey, result, null,
DateTime.Now.AddSeconds(60), TimeSpan.Zero);
}
}
}
return result;
}
}

The easiest way would be to handle caching in your repository provider. That way you don't have to change out any code in the rest of your app; it will be oblivious to the fact that the data was served out of a cache rather than the repository.
So, I'd create an interface that the controllers use to communicate with the backend, and in the implementation of this I'd add the caching logic. Wrap it all up in a nice bow with some DI, and your app will be set for easy testing.

Based on answer provided by Brendan, I defined a generic cached repository for the special case of relatively small lists that are rarely changed, but heavily read.
1. The interface
public interface IRepository<T> : IRepository
where T : class
{
IQueryable<T> AllNoTracking { get; }
IQueryable<T> All { get; }
DbSet<T> GetSet { get; }
T Get(int id);
void Insert(T entity);
void BulkInsert(IEnumerable<T> entities);
void Delete(T entity);
void RemoveRange(IEnumerable<T> range);
void Update(T entity);
}
2. Normal/non-cached repository
public class Repository<T> : IRepository<T> where T : class, new()
{
private readonly IEfDbContext _context;
public Repository(IEfDbContext context)
{
_context = context;
}
public IQueryable<T> All => _context.Set<T>().AsQueryable();
public IQueryable<T> AllNoTracking => _context.Set<T>().AsNoTracking();
public IQueryable AllNoTrackingGeneric(Type t)
{
return _context.GetSet(t).AsNoTracking();
}
public DbSet<T> GetSet => _context.Set<T>();
public DbSet GetSetNonGeneric(Type t)
{
return _context.GetSet(t);
}
public IQueryable AllNonGeneric(Type t)
{
return _context.GetSet(t);
}
public T Get(int id)
{
return _context.Set<T>().Find(id);
}
public void Delete(T entity)
{
if (_context.Entry(entity).State == EntityState.Detached)
_context.Set<T>().Attach(entity);
_context.Set<T>().Remove(entity);
}
public void RemoveRange(IEnumerable<T> range)
{
_context.Set<T>().RemoveRange(range);
}
public void Insert(T entity)
{
_context.Set<T>().Add(entity);
}
public void BulkInsert(IEnumerable<T> entities)
{
_context.BulkInsert(entities);
}
public void Update(T entity)
{
_context.Set<T>().Attach(entity);
_context.Entry(entity).State = EntityState.Modified;
}
}
3. Generic cached repository is based on non-cached one
public interface ICachedRepository<T> where T : class, new()
{
string CacheKey { get; }
void InvalidateCache();
void InsertIntoCache(T item);
}
public class CachedRepository<T> : ICachedRepository<T>, IRepository<T> where T : class, new()
{
private readonly IRepository<T> _modelRepository;
private static readonly object CacheLockObject = new object();
private IList<T> ThreadSafeCacheAccessAction(Action<IList<T>> action = null)
{
// refresh cache if necessary
var list = HttpRuntime.Cache[CacheKey] as IList<T>;
if (list == null)
{
lock (CacheLockObject)
{
list = HttpRuntime.Cache[CacheKey] as IList<T>;
if (list == null)
{
list = _modelRepository.All.ToList();
//TODO: remove hardcoding
HttpRuntime.Cache.Insert(CacheKey, list, null, DateTime.UtcNow.AddMinutes(10), Cache.NoSlidingExpiration);
}
}
}
// execute custom action, if one is required
if (action != null)
{
lock (CacheLockObject)
{
action(list);
}
}
return list;
}
public IList<T> GetCachedItems()
{
IList<T> ret = ThreadSafeCacheAccessAction();
return ret;
}
/// <summary>
/// returns value without using cache, to allow Queryable usage
/// </summary>
public IQueryable<T> All => _modelRepository.All;
public IQueryable<T> AllNoTracking
{
get
{
var cachedItems = GetCachedItems();
return cachedItems.AsQueryable();
}
}
// other methods come here
public void BulkInsert(IEnumerable<T> entities)
{
var enumerable = entities as IList<T> ?? entities.ToList();
_modelRepository.BulkInsert(enumerable);
// also inserting items within the cache
ThreadSafeCacheAccessAction((list) =>
{
foreach (var item in enumerable)
list.Add(item);
});
}
public void Delete(T entity)
{
_modelRepository.Delete(entity);
ThreadSafeCacheAccessAction((list) =>
{
list.Remove(entity);
});
}
}
Using a DI framework (I am using Ninject), one can easily define if a repository should be cached or not:
// IRepository<T> should be solved using Repository<T>, by default
kernel.Bind(typeof(IRepository<>)).To(typeof(Repository<>));
// IRepository<T> must be solved to Repository<T>, if used in CachedRepository<T>
kernel.Bind(typeof(IRepository<>)).To(typeof(Repository<>)).WhenInjectedInto(typeof(CachedRepository<>));
// explicit repositories using caching
var cachedTypes = new List<Type>
{
typeof(ImportingSystem), typeof(ImportingSystemLoadInfo), typeof(Environment)
};
cachedTypes.ForEach(type =>
{
// allow access as normal repository
kernel
.Bind(typeof(IRepository<>).MakeGenericType(type))
.To(typeof(CachedRepository<>).MakeGenericType(type));
// allow access as a cached repository
kernel
.Bind(typeof(ICachedRepository<>).MakeGenericType(type))
.To(typeof(CachedRepository<>).MakeGenericType(type));
});
So, reading from cached repositories is done without knowing about the caching. However, changing them requires to inject from ICacheRepository<> and calling the appropriate methods.

Related

Should I use singleton for DAL and Service classes?

My dal and service classes are as follows. I use Ninject to inject dependencies.
public interface IEntityRepository<T> where T : class, IEntity, new()
{
ICollection<T> GetAll(Expression<Func<T, bool>> filter = null);
T Get(Expression<Func<T, bool>> filter);
T Add(T entity);
T Update(T entity);
void Delete(T entity);
}
public class EfEntityRepositoryBase<TEntity, TContext> : IEntityRepository<TEntity>
where TEntity : class, IEntity, new()
where TContext : DbContext, new()
{
public virtual ICollection<TEntity> GetAll(Expression<Func<TEntity, bool>> filter = null)
{
using (var context = new TContext())
{
return (filter == null ? context.Set<TEntity>() : context.Set<TEntity>().Where(filter)).ToList();
}
}
public virtual TEntity Get(Expression<Func<TEntity, bool>> filter)
{
using (var context = new TContext())
{
return context.Set<TEntity>().SingleOrDefault(filter);
}
}
public virtual TEntity Add(TEntity entity)
{
using (var context = new TContext())
{
var addedEntity = context.Entry(entity);
addedEntity.State = EntityState.Added;
context.SaveChanges();
return entity;
}
}
public virtual TEntity Update(TEntity entity)
{
using (var context = new TContext())
{
var updatedEntity = context.Entry(entity);
updatedEntity.State = EntityState.Modified;
context.SaveChanges();
return entity;
}
}
public virtual void Delete(TEntity entity)
{
using (var context = new TContext())
{
var deletedEntity = context.Entry(entity);
deletedEntity.State = EntityState.Deleted;
context.SaveChanges();
}
}
}
public interface ICallService
{
}
public class CallManager : ICallService
{
}
public interface ICallDal : IEntityRepository<Call>
{
}
public class EfCallDal : EfEntityRepositoryBase<Call, DatabaseContext>, ICallDal
{
}
public class BusinessModule : NinjectModule
{
public override void Load()
{
Bind<ICallService>().To<CallManager>().InSingletonScope();
Bind<ICallDal>().To<EfCallDal>();
}
}
What are the advantages or disadvantages of using Singleton Scope in dal and service classes? Would it be right to use it according to your experience?
I'm also curious about the dependency injection of the DbContext class.
Bind<DbContext>().To<MyContext>().InSingletonScope();
I think using singleton for the context class is risky. Is not it?
What are the advantages or disadvantages of using Singleton Scope in
dal and service classes?
Advantages :
you instantiate only one object, gain in CPU and memory.
You can share state (which would be a huge disavantage if not controlled)
Disadvantages :
the object graph must be threadsafe (it is not the case of the DbContext)
the objects in the object graph must be stateless, unless you want the state being shared by all your objects
In practice this is not a good idea and it will a big source of problems.
As you seem to be in a web context (Asp.Net MVC), you should bind most of your objects InRequestScope.
Avoid using new DbContext. Your context should be bound and injected as constructor argument. Otherwise you miss the point of Dependency injection.
Once you have understood the mechanics of scoping, you will be able to play with singletons, and scoped factories and the like.

ASP.Net vNext DbContext Dependency Injection multiple request issues.

I am attempting to use ASP.Net vNext, MVC, EF7, and the repository pattern (not the issue here, I don't think)...
The issue I'm having is that when multiple requests are made against the database, I'm getting the following error: "There is already an open DataReader associated with this Command which must be closed first."
Here's some code:
public class Startup
{
public IConfiguration Configuration { get; set; }
public Startup(IHostingEnvironment env)
{
Configuration = new Configuration().AddJsonFile("config.json").AddEnvironmentVariables();
}
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
// Register Entity Framework
services.AddEntityFramework(Configuration)
.AddSqlServer()
.AddDbContext<MyDbContext>();
services.AddSingleton<ILocationRepo, LocationRepo>();
services.AddSingleton<IStateRepo, StateRepo>();
}
public void Configure(IApplicationBuilder app)
{
app.UseMvc();
var testData = ActivatorUtilities.CreateInstance<TestData>(app.ApplicationServices);
testData.InitializeData();
}
}
The controller:
[Route("api/[controller]")]
public class LocationsController : Controller
{
private readonly ILocationRepo _repo;
public LocationsController(ILocationRepo repo)
{
_repo = repo;
}
// GET: api/locations
[HttpGet]
public List<Location> Get()
{
return _repo.All.ToList();
}
// GET api/locations/5
[HttpGet("{id}")]
public IActionResult Get(int id)
{
var ret = _repo.GetById(id);
if (ret == null)
return new HttpNotFoundResult();
return new ObjectResult(ret);
}
// POST api/locations
[HttpPost]
public IActionResult Post([FromBody]Locationvalue)
{
var ret = _repo.AddOrUpdate(value);
if (ret == null)
return new BadRequestResult();
return new ObjectResult(ret);
}
// PUT api/locations/5
[HttpPut("{id}")]
public IActionResult Put(int id, [FromBody]Location value)
{
var ret = _repo.AddOrUpdate(value);
if (id == 0 || ret == null)
return new BadRequestResult();
return new ObjectResult(ret);
}
// DELETE api/locations/5
[HttpDelete("{id}")]
public IActionResult Delete(int id)
{
var existing = _repo.GetById(id);
if (existing == null)
return new HttpNotFoundResult();
bool ret = _repo.TryDelete(id);
return new ObjectResult(ret);
}
}
The States repository:
public class StateRepo : IStateRepo
{
private readonly MyDbContext context;
public StateRepo(MyDbContext diContext)
{
context = diContext;
}
public IEnumerable<State> All
{
get
{
return context.States;
}
}
public State GetById(int id)
{
return context.States.FirstOrDefault(x => x.Id == id);
}
}
I have pretty much the same repo setup for Locations (with a few more methods, of course)... the problem comes in when I'm making simultaneous AJAX calls to my locations and states controllers. I would expect the DI for the context to handle such collisions, but it doesn't appear to be doing so. Is there another way to configure this to work correctly without having to go back to the old way of creating an instance of my context throughout my repos? Do I have anything configured incorrectly?
I don't claim to be a DI expert, but try registering your repositories with AddScoped instead of AddSingleton. I think you are getting the same instance of the repository for each request which probably has the same instance of your DbContext and DbContext is not thread safe.
Also, make sure you have MultipleActiveResultSets=true in your connectionstring. I think that can also cause the error you are seeing.

controller post actionresult not saving changes to database

I have a post method in my controller that is not saving changes to my database (SQL express). I am using viewmodels and valueinjector to populate the VM from my model. I have checked and the values in the viewmodel and they have changed, but when I call my service:
fixedAssetService.SaveFixedAsset()
and bookmark the following in the service interface:
unitOfWork.Commit()
and pull up the quick watch window for unitOfWork, it has the old value.
All my tables have primary keys and I am using code first. The connection string is valid becasue I can get the items, I just can't save them.
My post method:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(FixedAssetViewModel evm)
{
var fixedAsset = fixedAssetService.GetFixedAsset(evm.FixedAssetId);
// Use Injector to handle mapping between viewmodel and model
fixedAsset.InjectFrom(evm);
try
{
if (ModelState.IsValid)
{
fixedAssetService.SaveFixedAsset();
return RedirectToAction("Details", "FixedAsset", new { id = fixedAsset.FixedAssetId });
}
}
catch (DataException)
{
//Log the error (add a variable name after DataException)
ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists, see your system administrator.");
}
}
My Service:
namespace FixedAssets.Services
{
public interface IFixedAssetService
{
IEnumerable<FixedAsset> GetAll();
IEnumerable<FixedAsset> FindBy(Expression<Func<FixedAsset, bool>> predicate);
FixedAsset GetFixedAsset(string id);
void CreateFixedAsset(FixedAsset fixedAsset);
void DeleteFixedAsset(string id);
void SaveFixedAsset();
bool ValueInUse(Expression<Func<FixedAsset, bool>> predicate);
}
public class FixedAssetService : IFixedAssetService
{
private readonly IFixedAssetRepository fixedAssetRepository;
private readonly IUnitOfWork unitOfWork;
public FixedAssetService(IFixedAssetRepository fixedAssetRepository, IUnitOfWork unitOfWork)
{
this.fixedAssetRepository = fixedAssetRepository;
this.unitOfWork = unitOfWork;
}
#region IFixedAssetService Members
public IEnumerable<FixedAsset> GetAll()
{
var fixedAssets = fixedAssetRepository.GetAll();
return fixedAssets;
}
public IEnumerable<FixedAsset> FindBy(Expression<Func<FixedAsset, bool>> predicate)
{
IEnumerable<FixedAsset> query = fixedAssetRepository.FindBy(predicate);
return query;
}
public bool ValueInUse(Expression<Func<FixedAsset, bool>> predicate)
{
IQueryable<FixedAsset> query = fixedAssetRepository.FindBy(predicate).AsQueryable();
int count = query.Count();
return count > 0 ? true : false;
}
public FixedAsset GetFixedAsset(string id)
{
var fixedAsset = fixedAssetRepository.GetById(id);
return fixedAsset;
}
public void CreateFixedAsset(FixedAsset fixedAsset)
{
fixedAssetRepository.Add(fixedAsset);
SaveFixedAsset();
}
public void DeleteFixedAsset(string id)
{
var fixedAsset = fixedAssetRepository.GetById(id);
fixedAssetRepository.Delete(fixedAsset);
SaveFixedAsset();
}
public void SaveFixedAsset()
{
unitOfWork.Commit();
}
#endregion
}
}
Edit: One thing I forgot to mention is this app was modeled almost exactly after an existing app that worked fine. Not sure if I have references messed up or what, but the other app uses the same methods only different entities
I found my problem. In the app I used as a model for this one I was using a separate unity class. My database factory registration was like this:
.RegisterType<IDatabaseFactory, DatabaseFactory>(new HttpContextLifetimeManager<IDatabaseFactory>())
Now I am using Microsoft.Practices.Unity and Unity.Mvc4 so I changed the registration to:
container.RegisterType<IDatabaseFactory, DatabaseFactory>();
per the comments in the bootstrapper class. When I changed it to:
container.RegisterType<IDatabaseFactory, DatabaseFactory>(new HierarchicalLifetimeManager());
per the suggestions on this post:
Stackoverflow thread
it finally worked!

Generic repository pattern and multiple selects

I am trying to learn the repository pattern and looking at a generic repository I cannot see how to handle customized select statements. For example, using this article the author uses a select by ID and a select all.
public interface IGenericRepository<T> where T:class
{
IEnumerable<T> SelectAll();
T SelectByID(object id);
void Insert(T obj);
void Update(T obj);
void Delete(object id);
void Save();
}
Later the article the IGenericRepository interface is implemented using Northwind. Then that is used to create a Customer controller.
public class CustomerController : Controller
{
private IGenericRepository<Customer> repository = null;
public CustomerController()
{
this.repository = new GenericRepository<Customer>();
}
...
This would handle selecting a list of all Customers or for one Customer by ID but where I get stuck is some more real world examples like "select all Customers for a client" or "select all Customers for a region". Plus, you could have another controller based on a different entity that would filter on different attributes. I assume I'm missing something basic. If the user interface needed to present the Customer entity (or any other entity) by various filters, how would this be done by sticking with one generic repository?
Here you go; to handle any select criteria apart from the Id, you can add Where method
like below
public interface IGenericRepository<T> where T:class
{
IEnumerable<T> SelectAll();
T SelectByID(object id);
IEnumerable<T> Where(Expression<Func<T,bool>> predicate)// this one
void Insert(T obj);
void Update(T obj);
void Delete(object id);
void Save();
}
Now in the Where method implementation do it like this
public IEnumerable<T> Where(Expression<Func<T,bool>> predicate)
{
return _objectSet.Where(predicate).AsEnumerable();
}
Here _objectSet in created in repository constructor like this :
public Repository(ObjectContext context)
{
_context = context;
_objectSet = _context.CreateObjectSet<T>();
}
public CustomerController()
{
_context = new NorthwindEntities();
_reporsitory = new Repository<Customer>(_context);
}
Use of Where method like
reporsitory.Where(c=>c.Country=="Canada").ToList();
For full reference see this project on codeplex (download /browse source code)
https://efgenericrepository.codeplex.com/SourceControl/latest
I think the implementation of the GenericRepository should somehow be able to return the IQueryable of current entity, like adding Get() method.
protected IQueryable<T> Get() // Notice that the access modifier is protected.
{
return table;
}
Then you could just create a derived class from GenericRepository and add a select method that accepts the Filter class.
public class CustomerRepository : GenericRepository<Customer>
{
public IEnumerable<T> SelectAll(CustomerFilter filter){ .. }
}
The filter class contains 2 filters.
public class CustomerFilter
{
public int? ClientId { get; set; }
public int? RegionId { get; set; }
}
Then the SelectAll implementation would be.
public IEnumerable<T> SelectAll(CustomerFilter filter)
{
var query = Get();
if (filter == null)
{
return query;
}
if (filter.ClientId.HasValue)
{
query = query.Where(q => q.ClientId == filter.ClientId.Value);
}
if (filter.RegionId.HasValue)
{
query = query.Where(q => q.RegionId == filter.RegionId.Value);
}
return query;
}
In the controller, calling it like.
public ActionResult Get(int? clientId, int? regionId)
{
var filter = new CustomerFilter { ClientId = clientId, RegionId = regionId };
var customers = _repository.SelectAll(filter);
return View();
}
You might need to see this post as your reference.
An approach I've seen in one asp.net mvc based mission critical app, is to use the generic interface as defined in the question. Then there is an abstract class that implements that interface. And there is one more repository class that inherits the abstract class, which has all methods specific to that class.
public interface IGenericRepository<T> where T:class
{
...
}
public abstract class GenericRepository<T> : IGenericRepository where T:class
{
...
}
And the CustomerRepository class
public class CustomerRepository : GenericRepository<Customer>
{
//add method specific to Customer like select Customers in specific country
}
And in the controller
public class CustomerController : Controller
{
private CustomerRepository repository = null;
public CustomerController()
{
this.repository = new CustomerRepository();
}
...

How to create Repository Classes in MVC3 (Entity Framework)?

I created a project using MVC3 - Entity Framework. I like to use Repository Pattern together with it. I am new to repository pattern. Do I need to create ONE EACH Repository for each Model Class (classes which represent each table in the database) and within each repository do I have to write all the functions which will Insert, Update, Delete and Fetch record?
No you don't. You can implement a GenericRepository for all your classes and then override it if you need to add functions. First i am gonna show you the unit of work. Through this class you can access all the repositories. I have added to this example one generic and one overrided:
public class UnitOfWork
{
FBDbContext context = new FBDbContext();
public FBDbContext Context { get { return context; } }
private BlockRepository BlockRepository;
private GenericRepository<Category> CategoryRepository;
#region RepositoryClasses
public IBlockRepository blockRepository
{
get
{
if (this.BlockRepository == null)
this.BlockRepository = new BlockRepository(context);
return BlockRepository;
}
}
public IGenericRepository<Category> categoryRepository
{
get
{
if (this.CategoryRepository == null)
this.CategoryRepository = new GenericRepository<Category>(context);
return CategoryRepository;
}
}
#endregion
public void Save()
{
context.SaveChanges();
}
}
Then you have the generic repository:
public class GenericRepository<TEntity>
{
internal FBDbContext context;
internal DbSet<TEntity> dbSet;
public GenericRepository(FBDbContext context)
{
this.context = context;
this.dbSet = context.Set<TEntity>();
}
public virtual TEntity Create()
{
return Activator.CreateInstance<TEntity>();
}
public IQueryable<TEntity> GetAll()
{
return dbSet;
}
//And all the functions you want in all your model classes...
}
and an example when you want to override the generic repository:
public class BlockRepository : GenericRepository<Block>
{
public BlockRepository(FBDbContext context) : base(context) { }
public IEnumerable<Block> GetByCategory(Category category)
{
return context.Blocks.Where(r => r.CategoryId == category.Id);
}
}
You can create common repository which will have common methods, all other repositories will be it's children:
public class MyModelRepository : GenericRepository<MyModel>
{
// extend
}
var MyModelRepository = new MyModelRepository();
See this, or google for "Generic Repository" :). If your don't need extended functionality for some model repository, then you can even not create repository class, instead do something like this:
var MyModelRepository = new GenericRepository<MyModel>();
Have an interface that represents the common operations between each repository. I.e. Insert, Update, Delete and Fetch:
public interface IRepository<T>
{
void Insert(T entity);
void Delete(T entity);
void Update(T entity);
void Fetch(T entity);
}
public class Repository<T> : IRepository<T>
/// your implementation
}
Then in each model you could define the repository to suit the context, for instance:
var repository1 = new Repository<ModelType>(dataContext);
repository1.Insert(obj);
var repository2 = new Repository<DifferentModelType>(dataContext);
repository2.Fetch(objects);
http://www.remondo.net/repository-pattern-example-csharp/

Resources