Complex business logic in repository - asp.net-mvc

I have a method in a repository with a very complex business logic. I just read that there should be no business logic in a repository.
Removing the business logic from this method will require me to distribute the logic among two other repositories (because it involves two other entities).
Then my question is -what pattern should I use to implement this complex logic? It will need to consume these three repositories, but I cannot place it in a controller because I need to reuse it. Thank you for your help.

Complex business logic usually goes into a service layer. A service may depend on one or more repositories to perform CRUD operations on your models. Thus a single service operation representing a business operation may depend on multiple simple operations. Then you could reuse this service layer in your controllers and other applications.
Obviously your service shouldn't depend on specific repository implementations. In order to provide a weaker coupling between the service layer and the repositories you could use interfaces. Here's an example:
public interface IProductsRepository { }
public interface IOrdersRepository { }
...
public interface ISomeService
{
void SomeBusinessOperation();
}
public class SomeServiceImpl: ISomeService
{
private readonly IProductsRepository _productsRepository;
private readonly IOrdersRepository _ordersRepository;
public SomeServiceImpl(
IProductsRepository productsRepository,
IOrdersRepository ordersRepository
)
{
_productsRepository = productsRepository;
_ordersRepository = ordersRepository;
}
public void SomeBusinessOperation()
{
// TODO: use the repositories to implement the business operation
}
}
Now all that's left is configure your DI framework to inject this specific service into your controller.
public class FooController : Controller
{
private readonly ISomeService _service;
public FooController(ISomeService service)
{
_service = service;
}
public ActionResult Index()
{
// TODO: Use the business operation here.
}
}
You can see how interfaces allow us to provide weak coupling between the layers. All the plumbing is performed by the DI framework and everything is transparent and easily unit testable.

I would use a domain driven design approach. A very good book on DDD is the following: .NET Domain-Driven Design with C#: Problem-Design-Solution. Look also for Fowlers Enterprise Patterns and Evans Domain Driven Design books. The basic idea is that a repository is basically infrastructure. All the domain logic goes into your model.
Example a repository method looks like this:
public void InsertAddresse(Company company)
{
foreach (Address address in company.Addresses)
{
this.InsertAddress(address, company.Key, (company.HeadquartersAddress == address));
}
}
On the other hand a model object looks like this:
public class Contact : Person, IAggregateRoot, IHasAddresses
{
private string jobTitle;
private string email;
private string phoneNumber;
private string mobilePhoneNumber;
private string faxNumber;
private string remarks;
private Company currentCompany;
private IList<Address> addresses;
public Contact()
: this(null)
{
}
public Contact(object key)
: this(key, null, null)
{
}
public Contact(object key, string firstName, string lastName)
: base(key, firstName, lastName)
{
this.jobTitle = string.Empty;
this.email = string.Empty;
this.phoneNumber = string.Empty;
this.mobilePhoneNumber = string.Empty;
this.faxNumber = string.Empty;
this.remarks = string.Empty;
this.currentCompany = null;
this.addresses = new List<Address>();
}
public string JobTitle
{
get { return this.jobTitle; }
set { this.jobTitle = value; }
}
public string Email
{
get { return this.email; }
set { this.email = value; }
}
public string PhoneNumber
{
get { return this.phoneNumber; }
set { this.phoneNumber = value; }
}
public string MobilePhoneNumber
{
get { return this.mobilePhoneNumber; }
set { this.mobilePhoneNumber = value; }
}
public string FaxNumber
{
get { return this.faxNumber; }
set { this.faxNumber = value; }
}
public string Remarks
{
get { return this.remarks; }
set { this.remarks = value; }
}
public Company CurrentCompany
{
get { return this.currentCompany; }
set { this.currentCompany = value; }
}
public IList<Address> Addresses
{
get { return this.addresses; }
}
protected override void Validate()
{
//some logic here
}
protected override BrokenRuleMessages GetBrokenRuleMessages()
{
return new ContactRuleMessages();
}
}

I think your super repository just break Single Responsibility Principle.
I would leave repository as simple as possible (KISS pattern ;), and would create other layer between controllers and repository, e.q. business layer.
To reuse and simplify the code have a look at Dependency Injection (implement IoC)
Actually I would suggest to have a look at SOLID principles.

Related

Ninject Conditional Self bind to change scope (For Task-scheduler) not working properly?

Within MVC Web Application DbContext binding work properly with InRequestScope()
kernel.Bind<DbContext>().ToSelf().InRequestScope();
kernel.Bind<IUnitOfWork<DbContext>>().To<UnitOfWork<DbContext>>();
But from a Task Scheduler call DbContext in InRequestScope() unable to update Db Table (without any error), until I change Binding to InSingletonScope() OR InThreadScope()
Question: So is their any way change scope to InSingletonScope() / InThreadScope() for a Task Scheduler Call. ?
// For Task Scheduler Call, I tried bellow bind, but not working properly
kernel.Bind<DbContext>().ToSelf()
.When(request => request.Target.Type.Namespace.StartsWith("NameSpace.ClassName"))
.InSingletonScope();
** And probably I miss some thing. Need help.
Code Snippet Updated
#region Commented Code
public EmailTask() : this
( DependencyResolver.Current.GetService<IMessageManager>(),
, DependencyResolver.Current.GetService<IUnitOfWork<DbContext>>()) { }
#endregion
public EmailTask(IMessageManager messageManager, IUnitOfWork<DbContext> unitOfWork)
{
this._messageManager = messageManager;
this._unitOfWork = unitOfWork;
ProcessEmail();
}
public class NonRequestScopedParameter : IParameter { ... }
public void ProcessEmail()
{
var temp = SomeRepository.GetAll();
SendEmail(temp);
temp.Date = DateTime.Now;
SomeRepository.Update(temp);
unitOfWork.Commit();
}
public class ExecuteEmailTask : ITask
{
private readonly IResolutionRoot _resolutionRoot;
private int _maxTries = 5;
public ExecuteEmailTask(IResolutionRoot resolutionRoot)
{
_resolutionRoot = resolutionRoot;
}
public void Execute(XmlNode node)
{
XmlAttribute attribute1 = node.Attributes["maxTries"];
if (attribute1 != null && !String.IsNullOrEmpty(attribute1.Value))
{
this._maxTries = int.Parse(attribute1.Value);
}
/// send email messages
var task = _resolutionRoot.Get<EmailTask>(new NonRequestScopedParameter());
}
}
In Web.Config
<ScheduleTasks>
<Thread seconds="60">
<task name="ExecuteEmailTask" type="namespace.ExecuteEmailTask, AssemblyName" enabled="true" stopOnError="false" maxTries="5"/>
</Thread>
</ScheduleTasks>
In Global.asax
protected void Application_Start()
{
/* intialize Task */
TaskConfig.Init();
TaskManager.Instance.Initialize(TaskConfig.ScheduleTasks);
TaskManager.Instance.Start();
}
Ninject Bind Syntax
kernel.Bind<DbContext>().ToSelf().InRequestScope(); // Default bind
kernel.Bind<DbContext>().ToSelf()
.When(x => x.Parameters.OfType<NonRequestScopedParameter>().Any())
.InCallScope(); // For Scheduler
Note: EmailTask class also have SomeReposity as a Constructor Argument.
Queries:-
But what is the bind syntax to resolve TaskScheduler(IResolutionRoot resolutionRoot) ?
What is the configuration code to run TaskScheduler ?
As say to put IFakeDbContext directly into constructor, can this work with IUnitOfWork<FakeDbContext> ?
Problem
Task unable to call with Overloaded Constructor , it is only able to call TaskScheduler default Constructor.
Question 4: Can any way to invoke TaskScheduler(IResolutionRoot resolutionRoot) from TaskScheduler default constructor ?
Sample Code Snippet to create Task & run using System.Threading.Timer
private ITask createTask()
{
if (this.Enabled && (this._task == null))
{
if (this._taskType != null)
{
this._task = Activator.CreateInstance(this._taskType) as ITask;
}
this._enabled = this._task != null;
}
return this._task;
}
Question 5: Can I resolve TaskScheduler(IResolutionRoot resolutionRoot) here ?
Solved
public ExecuteEmailTask() :
this(DependencyResolver.Current.GetService<IResolutionRoot>())
OR
public ExecuteEmailTask() : this(new Bootstrapper().Kernel) { }
public ExecuteEmailTask(IResolutionRoot resolutionRoot)
{
_resolutionRoot = resolutionRoot;
}
First of, you should note that InSingletonScope() is usually a bad idea for DbContext's/Sessions. What happens if some other service changes data in the meantime? I would recommend investigating what effects this has.
For the scenario you first described, a correctly formulated .When(...) should work.
As an alternative to the .When(...) binding you could also use a .Named("FooBar") binding.
The constructor of the scheduled task would then need to look like:
ctor(Named["FooBar"] DbContext dbContext);
However, note, that this only (easily) works in case you need to inject the DbContext into a single constructor. If the task features dependencies and these need the same DbContext instance, too, it gets a bit tricker.
Since you updated your answer and say that this is the case, i would recommend an entirely different approach: Using a request parameter as basis for the When(...) condition combined with InCallScope binding. See below for an example.
Brace yourself, this is ab it of code :) The implementation requires the ninject.extensions.NamedScope extension (nuget).
I've also used xUnit and FluentAssertions nuget packages to execute the tests.
public class Test
{
// the two implementations are just for demonstration and easy verification purposes. You will only use one DbContext type.
public interface IFakeDbContext { }
public class RequestScopeDbContext : IFakeDbContext { }
public class CallScopeDbContext : IFakeDbContext { }
public class SomeTask
{
public IFakeDbContext FakeDbContext { get; set; }
public Dependency1 Dependency1 { get; set; }
public Dependency2 Dependency2 { get; set; }
public SomeTask(IFakeDbContext fakeDbContext, Dependency1 dependency1, Dependency2 dependency2)
{
FakeDbContext = fakeDbContext;
Dependency1 = dependency1;
Dependency2 = dependency2;
}
}
public class Dependency1
{
public IFakeDbContext FakeDbContext { get; set; }
public Dependency1(IFakeDbContext fakeDbContext)
{
FakeDbContext = fakeDbContext;
}
}
public class Dependency2
{
public IFakeDbContext FakeDbContext { get; set; }
public Dependency2(IFakeDbContext fakeDbContext)
{
FakeDbContext = fakeDbContext;
}
}
public class TaskScheduler
{
private readonly IResolutionRoot _resolutionRoot;
public TaskScheduler(IResolutionRoot resolutionRoot)
{
_resolutionRoot = resolutionRoot;
}
public SomeTask CreateScheduledTaskNow()
{
return _resolutionRoot.Get<SomeTask>(new NonRequestScopedParameter());
}
}
public class NonRequestScopedParameter : Ninject.Parameters.IParameter
{
public bool Equals(IParameter other)
{
if (other == null)
{
return false;
}
return other is NonRequestScopedParameter;
}
public object GetValue(IContext context, ITarget target)
{
throw new NotSupportedException("this parameter does not provide a value");
}
public string Name
{
get { return typeof(NonRequestScopedParameter).Name; }
}
// this is very important
public bool ShouldInherit
{
get { return true; }
}
}
[Fact]
public void FactMethodName()
{
var kernel = new StandardKernel();
// this is the default binding
kernel.Bind<IFakeDbContext>().To<RequestScopeDbContext>();
// this binding is _only_ used when the request contains a NonRequestScopedParameter
// in call scope means, that all objects built in the a single request get the same instance
kernel.Bind<IFakeDbContext>().To<CallScopeDbContext>()
.When(x => x.Parameters.OfType<NonRequestScopedParameter>().Any())
.InCallScope();
// let's try it out!
var task = kernel.Get<SomeTask>(new NonRequestScopedParameter());
// verify that the correct binding was used
task.FakeDbContext.Should().BeOfType<CallScopeDbContext>();
// verify that all children of the task get injected the same task instance
task.FakeDbContext.Should()
.Be(task.Dependency1.FakeDbContext)
.And.Be(task.Dependency2.FakeDbContext);
}
}
Since, as you say, the task scheduler does not make use of the IoC to create the task, it only supports a parameterless constructor. In that case you can make use DependencyResolver.Current (however, note that i'm in no way an expert on asp.net /MVC so i'm not making any claims that this is thread safe or working 100% reliably):
public class TaskExecutor : ITask
{
public TaskExecutor()
: this(DependencyResolver.Current.GetService<IResolutionRoot>())
{}
internal TaskExecutor(IResolutionRoot resolutionRoot)
{
this.resolutionRoot = resolutionRoot;
}
public void Execute()
{
IFooTask actualTask = this.resolution.Get<IFooTask>(new NonRequestScopedParameter());
actualTask.Execute();
}
}

Unit Testing a mock WCF client

I'm having serious issues in how to deploy a WCF client in a MVC site which is easily testable. I'm struggling to set up a mock of the service without actually accessing a endpoint.
Example Controller of site under test
public class ProfileController : ControllerExtended
{
public ProfileController(IUserService membershipService, IDropDownService dropdownService, ISiteService siteService)
{
WCFService.Instance.Client = siteService; //Should maybe be a serpate service.
_membershipService = membershipService;
_dropDownService = dropdownService;
_siteService = siteService;
}
public ActionResult Index()
{
UserComp profile = _siteService.ProfileGet(_sharedContext.CurrentUser.id);
return View(new ProfileViewModel { Profile = profile });
}
}
WCF Singleton (I think my implementation of WCF is my issue, should it be in a interface?)
public sealed class WCFService
{
public SiteServiceI Client { get; set; }
#region Singleton
static readonly WCFService query = new WCFService();
static WCFService()
{
}
WCFService()
{
}
public static WCFService Instance
{
get { return query; }
}
#endregion
}
UnitTest
[TestFixture]
public class UnitTest1
{
private Mock<SiteService> mockSiteService;
private Mock<IUserService> mockMembershipService;
private Mock<IDropDownService> mockDropDown;
private Mock<SiteServiceIClient> mockServiceClient; //new Mock<SiteServiceIClient>();
//private Mock<WebService> mockWebService;
[SetUp]
public void SetUp()
{
mockSiteService = new Mock<ISiteService>();
mockMembershipService = new Mock<IUserService>();
mockDropDown = new Mock<IDropDownService>();
mockServiceClient = new Mock<SiteServiceIClient>();
mockWebService = new Mock<WebService>(mockServiceClient);
}
[Test]
public void CheckHomeIndex_Controller()
{
var controller = new HomeController(mockMembershipService.Object, mockDropDown.Object, mockPTSearch.Object, mockServiceClient.Object); // mockServiceClient times out.
Assert.AreEqual("this", "this");
}
}
I assume the errors are occurring because the singleton sets the service up as soon as it is initialised. I've tried to implement a separate service purely for called to WCF but not had success in implementing it in a testable manner. Not too sure if this is to vague but I've read a lot on it and not an closer.
The singleton is definitely your problem - testing with singletons is entering a world of pain. You should implement a facade pattern to make this testing friendly. Something like this:
public interface IServiceFacade
{
Profile ProfileGet(int id);
}
public class ServiceFacade : IServiceFacade
{
private WCFService _theRealService = new WCFService();
public Profile ProfileGet(int id)
{
return _theRealService.ProfileGet(id);
}
}
public class Some_Tests()
{
public void Test_Stuff_Whatever()
{
Mock<IServiceFacade> _facade = new Mock<IServiceFacade>();
_facade.SetUp(Whatever.....);
}
}
Your problem is that your service is singleton. The problem of singleton pattern is that it is not testable. You should use Dependency injection to get service.

How to avoid repositories that duplicate code

I have successfully setup a simple mvc application that lists teams. I'm using Ninject to inject the appropriate repository depending on the controller (thanks to stack overflow ;). All looks good, except that the repository code looks exactly the same. And I know that's wrong. So my TeamRepository has two classes (for now).
public class SwimTeamRepository : ITeamRepository<SwimTeam>
{
private readonly Table<SwimTeam> _teamTable;
public SwimTeamRepository(string connectionString)
{
_teamTable = (new DataContext(connectionString).GetTable<SwimTeam>());
}
public IQueryable<SwimTeam> Team
{
get { return _teamTable; }
}
}
public class SoccerTeamRepository : ITeamRepository<SoccerTeam>
{
private readonly Table<SoccerTeam> _teamTable;
public SoccerTeamRepository(string connectionString)
{
_teamTable = (new DataContext(connectionString).GetTable<SoccerTeam>());
}
public IQueryable<SoccerTeam> Team
{
get { return _teamTable; }
}
}
They look exactly the same except for the Class and Table name, so clearly I need to re-factor this. What would be the best approach here? Singleton? Factory Method?
Thanks in advance!
You could use generics:
public interface ITeamRepository<T>
{
}
public class TeamRepository<TTeam> : ITeamRepository<TTeam>
where TTeam : Team
{
private readonly Table<TTeam> _teamTable;
public TeamRepository(string connectionString)
{
_teamTable = (new DataContext(connectionString).GetTable<TTeam>());
}
public IQueryable<TTeam> Team
{
get { return _teamTable; }
}
}
public class Team
{
}
public class SwimTeam : Team
{
}
Then use it like so...
public void MyMethod()
{
var repository = new TeamRepository<SwimTeam>();
}
...and set up your IoC container w/ Ninject like so...
public class MyModule : NinjectModule
{
public override void Load()
{
Bind<ITeamRepository<SwimTeam>>
.To<TeamRepository<SwimTeam>>();
}
}
public void MyMethod()
{
var repository = kernel.Get<ITeamRepository<SwimTeam>>();
}
If you want to get REAL generic and have a single repository for ALL of your mapped classes, you can do something like this:
public interface IRepository
{
IQueryable<T> Get<T>() where T : class, new();
}
public class Repository : IRepository, IDisposable
{
private DataContext _dataContext;
public Repository(string connectionString)
{
_dataContext = new DataContext(connectionString);
}
public IQueryable<T> Get<T>()
where T : class, new()
{
return _dataContext.GetTable<T>().AsQueryable();
}
public void Dispose()
{
if (_dataContext != null)
{
_dataContext.Dispose();
_dataContext = null;
}
}
}
...which you could call like so (after setting up your Ninject container)...
using (var repository = kernel.Get<IRepository>())
{
var swimTeam = repository.Get<SwimTeam>();
}
Since Ninject takes care of the life-cycle management of your objects, you don't HAVE to wrap the repository in a using statement. In fact, you don't want to use a using statement there at all if you plan to use the repository more than once within the scope of its lifetime. Ninject will automatically dispose of it when it's life-cycle ends.
Here's a good article by Rob Conery on using this kind of technique to reduce the friction of using different ORMs.
EDIT by keeg:
I Think
public class TeamRepository<TTeam> : ITeamRepository<TTeam> where TTeam : Team {}
Should be
public class TeamRepository<TTeam> : ITeamRepository<TTeam> where TTeam : class {}
Please correct if I'm wrong.
Is this what you want?
public class TeamRepository : ITeamRepository<T>
{
private readonly Table<T> _teamTable;
public TeamRepository(string connectionString)
{
_teamTable = (new DataContext(connectionString).GetTable<T>());
}
public IQueryable<T> Team
{
get { return _teamTable; }
}
}

ASP.NET MVC 3 Application using Ninject, Entity Framework 4 Code-First CTP 5, Patterns

I've tried to build some base project with above technologies. I wanted maximum flexibility and testability so I tried to use patterns along the way to make this as a base for future projects. However, it seem
something is wrong or whatever and I really need help here. So i have two questions :
Is there anything wrong with my current code? I've applied patterns correctly? Any suggestions or recommendation that would lead me in the right direction?
Why do this code actually connect to the database, create it, but doesn't support insert even if I perform the corrects operation? (Look at the end of the post for details about this error) FIXED
I believe this could also help others since I haven't found enough information in order to make something up correctly. I am pretty sure lots of people try to do it the right way and are not sure like me if what I am doing is right.
I have two entities: Comment and Review
COMMENT
public class Comment
{
[Key]
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual string Author { get; set; }
public virtual string Body { get; set; }
}
REVIEW
public class Review
{
[Key]
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual string Author { get; set; }
public virtual string Body { get; set; }
public virtual bool Visible { get; set; }
public IEnumerable<Comment> Comments { get; set; }
}
I built up a base repository for each of them this way :
GENERIC REPOSITORY
public abstract class EFRepositoryBase<T> : IRepository<T> where T : class
{
private Database _database;
private readonly IDbSet<T> _dbset;
protected IDatabaseFactory DatabaseFactory { get; private set; }
protected Database Database { get { return _database ?? (_database = DatabaseFactory.Get()); } }
public EFRepositoryBase(IDatabaseFactory databaseFactory)
{
DatabaseFactory = databaseFactory;
_dbset = Database.Set<T>();
}
public virtual void Add(T entity)
{
_dbset.Add(entity);
}
public virtual void Delete(T entity)
{
_dbset.Remove(entity);
}
public virtual T GetById(long id)
{
return _dbset.Find(id);
}
public virtual IEnumerable<T> All()
{
return _dbset.ToList();
}
}
For specific operations, I use an interface:
public interface IReviewRepository : IRepository<Review> {
// Add specific review operations
IEnumerable<Review> FindByAuthor(string author);
}
So I am getting the generics operations from the abstract class plus the specific operations:
public class EFReviewRepository : EFRepositoryBase<Review>, IReviewRepository
{
public EFReviewRepository(IDatabaseFactory databaseFactory)
: base(databaseFactory)
{ }
public IEnumerable<Review> FindByAuthor(string author)
{
return base.Database.Reviews.Where(r => r.Author.StartsWith(author))
.AsEnumerable<Review>();
}
}
As you figured out, I also use a database factory will produce the database context :
DATABASE FACTORY
public class DatabaseFactory : Disposable, IDatabaseFactory
{
private Database _database;
public Database Get()
{
return _database ?? (_database = new Database(#"AppDb"));
}
protected override void DisposeCore()
{
if (_database != null)
_database.Dispose();
}
}
DISPOSABLE (Some extensions methods...)
public class Disposable : IDisposable
{
private bool isDisposed;
~Disposable()
{
Dispose(false);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool disposing)
{
if (!isDisposed && disposing)
{
DisposeCore();
}
isDisposed = true;
}
protected virtual void DisposeCore()
{
}
}
DATABASE
public class Database : DbContext
{
private IDbSet<Review> _reviews;
public IDbSet<Review> Reviews
{
get { return _reviews ?? (_reviews = DbSet<Review>()); }
}
public virtual IDbSet<T> DbSet<T>() where T : class
{
return Set<T>();
}
public Database(string connectionString)
: base(connectionString)
{
//_reviews = Reviews;
}
public virtual void Commit()
{
base.SaveChanges();
}
/*
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// TODO: Use Fluent API Here
}
*/
}
And to finish, I have my unit of work....
UNIT OF WORK
public class UnitOfWork : IUnitOfWork
{
private readonly IDatabaseFactory _databaseFactory;
private Database _database;
public UnitOfWork(IDatabaseFactory databaseFactory)
{
_databaseFactory = databaseFactory;
}
protected Database Database
{
get { return _database ?? (_database = _databaseFactory.Get()); }
}
public void Commit()
{
Database.Commit();
}
}
I also bound using Ninject the interfaces:
NINJECT CONTROLLER FACTORY
public class NinjectControllerFactory : DefaultControllerFactory
{
// A Ninject "Kernel" is the thing that can supply object instances
private IKernel kernel = new StandardKernel(new ReviewsDemoServices());
// ASP.NET MVC calls this to get the controller for each request
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
if (controllerType == null)
return null;
return (IController)kernel.Get(controllerType);
}
private class ReviewsDemoServices : NinjectModule
{
public override void Load()
{
// Bindings...
Bind<IReviewRepository>().To<EFReviewRepository>();
Bind<IUnitOfWork>().To<UnitOfWork>();
Bind<IDatabaseFactory>().To<DatabaseFactory>();
Bind<IDisposable>().To<Disposable>();
}
}
}
However, when I call in the constructor (the default action) ...
public class ReviewController : Controller
{
private readonly IReviewRepository _reviewRepository;
private readonly IUnitOfWork _unitOfWork;
public ReviewController(IReviewRepository postRepository, IUnitOfWork unitOfWork)
{
_reviewRepository = postRepository;
_unitOfWork = unitOfWork;
}
public ActionResult Index()
{
Review r = new Review { Id = 1, Name = "Test", Visible = true, Author = "a", Body = "b" };
_reviewRepository.Add(r);
_unitOfWork.Commit();
return View(_reviewRepository.All());
}
}
This seem to create the database but doesnt't insert anything in the database in EF4. It seem that I may figured out the problem.. while looking at the database object.. the connection state is closed and server version throw an exception of this kind :
ServerVersion = '(((System.Data.Entity.DbContext (_database)).Database.Connection).ServerVersion' threw an exception of type 'System.InvalidOperationException'
I am doing the right things? Is there anything wrong in what I've built ?
Also if you have recommandation about the code I posted, I would be glad. I am just trying to the learn the right way for building any kind of application in MVC 3. I want a good a start.
I use :
Entity Framework 4 with Code-First
ASP.NET MVC 3
Ninject as DI Container
SQL Server Express (not R2)
Visual Studio 2010 Web Express
Eww. This one was sneaky. Actually i don't know ninject much so i couldnt figure it out right away.
I found the solution for the SECOND question which was related to the error by finding that ninject actually shoot two instance of the DatabaseFactory, one for the repository and one for the unit of work. Actually, the error was not the problem. It was an internal error in the object database but its normal i think since im using Entity Framework.
The real problem was that Ninject was binding two different instance of IDatabaseFactory which lead to 2 connection open.
The review was added to the first set in _reviewRepostory which was using the first instance of the Database.
When calling commit on the unit of work.. it saved nothing due to the fact that the review wasnt on this database instance. In fact, the unit of work called the databasefactory which lead to creating a new instance since ninject sent a new instance of it.
To fix it simply use :
Bind<IDatabaseFactory>().To<DatabaseFactory>().InSingletonScope();
instead of
Bind<IDatabaseFactory>().To<DatabaseFactory>();
And now all the system work correctly!
Now, would love some answers regarding the first question which was if there anything wrong with my current code ? Ive applied patterns correctly ? Any suggestions or recommendation that would lead me in the right direction ?
One small observation: by having your EFRepositoryBase and IReviewRepository have methods that return an IEnumerable<> instead of an IQueryable<>, you prevent subsequent methods from adding filter expressions/constraints or projections or so on to the query. Instead, by using IEnumerable<>, you will do any subsequent filtering (e.g. using LINQ extension methods) on the full result set, rather than allowing those operations to affect and simplify the SQL statement that gets run against the datastore.
In other words, you are doing further filtering at the webserver level, not at the database level where it really belongs if possible.
Then again, this may be intentional - sometimes using IEnumerable<> is valid if you do want to prevent callers of your function from modifying the SQL that is generated, etc.

Caching Data Objects when using Repository/Service Pattern and 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.

Resources