I have a MVC app using the UnitOfWork, Service Layer, Repository Pattern and EF4 as the ORM.
My question is does this (UnitOfWork) having a property that is the Context to the EF tightly couple my layers?
Unit Of Work
Public Interface IUnitOfWork
Inherits IDisposable
Property Context As GTGContext
Sub Commit()
End Interface
Public Class UnitOfWork
Implements IUnitOfWork
Public Property Context As Domain.GTGContext Implements IUnitOfWork.Context
Public Sub New()
_Context = New GTGContext
End Sub
Public Sub Commit() Implements IUnitOfWork.Commit
_Context.SaveChanges()
End Sub
#Region "IDisposable Support"
Private _IsDisposed As Boolean
Protected Overridable Sub Dispose(ByVal Disposing As Boolean)
If (Not _IsDisposed) Then
If (Disposing) Then
If (_Context IsNot Nothing) Then
_Context.Dispose()
End If
End If
'TODO: Free unmanaged resources (unmanaged objects) and override Finalize() below.
End If
_IsDisposed = True
End Sub
'TODO: Override Finalize() only if Dispose(ByVal disposing As Boolean) above has code to free unmanaged resources.
'Protected Overrides Sub Finalize()
' Dispose(False)
' MyBase.Finalize()
'End Sub
Public Sub Dispose() Implements IDisposable.Dispose
Dispose(True)
GC.SuppressFinalize(Me)
End Sub
#End Region
End Class
Service
Public Class CustomerService
Private _UOW As IUnitOfWork
Public Sub New(UOW As IUnitOfWork)
_UOW = UOW
End Sub
End Class
Repository
Imports System.Data.Objects
Namespace Repositories
Public Interface IRepository(Of T As Class)
ReadOnly Property ObjectSet As IObjectSet(Of T)
ReadOnly Property UnitOfWork As IUnitOfWork
Function Query(ByVal Expression As Expressions.Expression(Of Func(Of T, Boolean))) As IQueryable(Of T)
Function GetFirst(ByVal Expression As Expressions.Expression(Of Func(Of T, Boolean))) As T
Function GetSingle(ByVal Expression As Expressions.Expression(Of Func(Of T, Boolean))) As T
Sub Add(ByVal Entity As T)
Sub Attach(ByVal Entity As T)
Sub Delete(ByVal Entity As T)
Sub SaveChanges()
End Interface
End Namespace
Imports System.Data.Objects
Namespace Repositories
Public Class Repository(Of T As Class)
Implements IRepository(Of T)
#Region "Private Members/Properties"
Private _ObjectSet As IObjectSet(Of T)
Private ReadOnly Property ObjectSet As System.Data.Objects.IObjectSet(Of T) Implements IRepository(Of T).ObjectSet
Get
If (_ObjectSet Is Nothing) Then
_ObjectSet = UnitOfWork.Context.CreateObjectSet(Of T)()
End If
Return _ObjectSet
End Get
End Property
Private _UnitOfWork As IUnitOfWork
Private ReadOnly Property UnitOfWork As IUnitOfWork Implements IRepository(Of T).UnitOfWork
Get
Return _UnitOfWork
End Get
End Property
#End Region
#Region "Constructor(s)"
Public Sub New(ByVal UnitOfWork As IUnitOfWork)
If (UnitOfWork Is Nothing) Then
Throw New ArgumentNullException("UnitOfWork")
End If
_UnitOfWork = UnitOfWork
End Sub
#End Region
#Region "IRepository(Of T)"
Public Sub Add(ByVal Entity As T) Implements IRepository(Of T).Add
ObjectSet.AddObject(Entity)
End Sub
Public Sub Attach(ByVal Entity As T) Implements IRepository(Of T).Attach
ObjectSet.Attach(Entity)
UnitOfWork.Context.ObjectStateManager.ChangeObjectState(Entity, EntityState.Modified)
End Sub
Public Sub Delete(ByVal Entity As T) Implements IRepository(Of T).Delete
ObjectSet.DeleteObject(Entity)
End Sub
Public Function GetFirst(ByVal Expression As System.Linq.Expressions.Expression(Of System.Func(Of T, Boolean))) As T Implements IRepository(Of T).GetFirst
Return ObjectSet.FirstOrDefault(Expression)
End Function
Public Function GetSingle(ByVal Expression As System.Linq.Expressions.Expression(Of System.Func(Of T, Boolean))) As T Implements IRepository(Of T).GetSingle
Return ObjectSet.SingleOrDefault(Expression)
End Function
Public Function Query(ByVal Expression As System.Linq.Expressions.Expression(Of System.Func(Of T, Boolean))) As System.Linq.IQueryable(Of T) Implements IRepository(Of T).Query
Return ObjectSet.Where(Expression)
End Function
Public Sub SaveChanges() Implements IRepository(Of T).SaveChanges
UnitOfWork.Commit()
End Sub
#End Region
End Class
End Namespace
That's OK, just make sure you to pick proper naming for it like UnitOfWorkEF. You should also remove the EF context from the IUnitOfWork interface as it would be tightly coupled to the data access technology. You could instead have the context only inside the specific UnitOfWorkEF class.
I would make EFContext implement IUnitOfWork since context is partial class.
public partial class MyContenxt : IUnitOfWork {
public void Commit() {
this.SaveChanges();
}
}
Related
I receive the following error while trying to inject one of my components:
No constructors on type 'Event.Function.Components.EventComponent' can be found with the constructor finder 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder'
As you can see, I am trying to inject the following components:
DependencyInjection.Initialize(builder =>
{
builder.RegisterType<DatabaseContext>().As<IDatabaseContext>()
.WithParameter("connectionString", ConfigurationManager.AppSettings["connectionString"].ToString());
builder.RegisterType<Repository>().As<IRepository>().SingleInstance().PropertiesAutowired();
builder.RegisterType<EventComponent>().As<IEventComponent>().SingleInstance().PropertiesAutowired();
builder.RegisterType<CommentComponent>().As<ICommentComponent>().SingleInstance().PropertiesAutowired();
}, functionName);
Below please find the class objects I am trying to inject.
public class DatabaseContext : DbContext, IDatabaseContext
{
public DatabaseContext(string connectionString) : base(connectionString)
{
}
}
public class Repository : IRepository
{
protected readonly IDatabaseContext Context;
public Repository(IDatabaseContext context)
{
Context = context;
}
}
public class EventComponent : IEventComponent
{
private readonly IRepository _repository;
private EventComponent(IRepository repo)
{
_repository = repo;
}
}
I am using .PropertiesAutoWired(), which gives the following definition, and according to my understanding, should know what IRepository is, since it is registered in the container.
Configure the component so that any properties whose types are registered in the container will be wired to instances of the appropriate service.
Am I doing something wrong?
Posting it here as it will hopefully help someone else, and maybe my future self.
After posting, I realized the constructor on my EventComponent is private, and it should be public.
So I changed:
public class EventComponent : IEventComponent
private readonly IRepository _repository;
private EventComponent(IRepository repo)
{
_repository = repo;
}
}
To:
public class EventComponent : IEventComponent
private readonly IRepository _repository;
public EventComponent(IRepository repo)
{
_repository = repo;
}
}
The following Exception occurs when i inject the UserRepository Interface in to the controller:
EJB Invocation failed on component UserRepositoryMock for method public abstract java.util.List com.test.repository.IRepository.all(): javax.ejb.EJBTransactionRolledbackException: WFLYEE0042: Failed to construct component instance
I'm not sure, maybe the inheritance hierachy could be a problem:
IRepository is implemented by IUserRepository. Then I've an abstract class AbstractRepository that also implements IRepository.
The UserRepositoryMock extends AbstractRepository and implements the IUserRepository Interface.
In Code:
#Singleton
#Alternative
public class UserRepositoryMock extends AbstractRepository<IUser> implements IUserRepository {
#EJB
private IUserFactory userFactory;
public UserRepositoryMock(){
userFactory.generateFirstUser()
}
}
AbstractRepository
#Singleton
public abstract class AbstractRepository<T extends IBO> implements IRepository<T> {
#Override
public List<T> all(){....}
}
IUserRepository:
public interface IUserRepository extends IRepository<IUser>{
...
}
Other injections working fine, any ideas?
I would suggest to change this:
public UserRepositoryMock(){
userFactory.generateFirstUser();
}
to something like:
#PostConstruct
public void setup() {
userFactory.generateFirstUser();
}
I am trying to pass my unitofwork into my generic base repository, but when i try and call some of the methods the unitofwork isnt being passed into the base repository.
The scenario: I inject the userRepository below into my UserController all fine, its when it calls the userRepository.Save(user) it fails due to the unitofwork being null. Im not sure why though?
Im using nhibernate and structuremap. I think ive wired everything up correctly but here is some code to double check:
Here is the base repository:
public class BaseRepository<T> : IRepository<T> where T : IAggregateRoot
{
private readonly IUnitOfWork _unitOfWork;
public BaseRepository(IUnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;
}
public BaseRepository()
{}
public void Save(T Entity)
{
_unitOfWork.Session.Save(Entity);
}
}
A specific repository:
public class UserRepository : BaseRepository<User>, IUserRepository
{
}
This is my nhibernate structuremap configuration:
public NhibernateRegistry()
{
For<IUnitOfWork>().HybridHttpOrThreadLocalScoped().Use<UnitOfWork>();
For(typeof(IRepository<>)).Use(typeof(BaseRepository<>));
// Nhibernate Session
For<ISession>().HybridHttpOrThreadLocalScoped().Use(context => context.GetInstance<ISessionFactory>().OpenSession());
// Nhibernate SessionFactory
For<ISessionFactory>().Singleton().Use(NhibernateHelper.CreateSessionFactory());
}`
Here is my nhibernate http module:
public class NHibernateModule : IHttpModule
{
private IUnitOfWork _unitOfWork;
public void Init(HttpApplication context)
{
context.BeginRequest += ContextBeginRequest;
context.EndRequest += ContextEndRequest;
}
private void ContextBeginRequest(object sender, EventArgs e)
{
_unitOfWork = ObjectFactory.GetInstance<IUnitOfWork>();
}
private void ContextEndRequest(object sender, EventArgs e)
{
try { _unitOfWork.Commit(); }
catch { _unitOfWork.Rollback(); }
finally { Dispose(); }
}
public void Dispose()
{
if (_unitOfWork != null)
_unitOfWork.Dispose();
}
}
UserRepository needs a constructor that takes in the IUnitOfWork and passes it to the BaseRepository constructor. Currently, UserRepository is using the parameterless constructor of BaseRepository, so no IUnitOfWork is injected. Get rid of the parameterless constructor, and make sure all derived types pass the IUnitOfWork to the base.
I am using the Service/Repository/EF/POCO pattern in a MVC app, and had a couple questions about the Interfaces.
1) Should I make an Interface per Service?
2) Should I make an Interface per Repository?
Or, should I have a generic interface per layer (IService(Of T), IRepository(Of T)).
What I dont understand is how in the controller say, it takes a IService(Of Category) interface in it's constructor, how do I implements the methods in the concrete class?
Public Class HomeController
Inherits System.Web.Mvc.Controller
Private _Service As IService(Of Category)
Public Sub New(ByVal Service As IService(Of Category))
_Service = Service
End Sub
Function Index() As ActionResult
Return View()
End Function
End Class
The _Service does not have the methods of my concrete CategoryService class?
Make any sense?
Use concrete interface for service. If your services can be described by generic interface you most probably don't need them at all. Generic interface is often used for repositories because repositories usually offer same core methods.
For myself, I use a generic session object that is strongly type, this class is in my domain project witch contains all my domain classes. You should take a look at this post : http://weblogs.asp.net/scottgu/archive/2010/07/16/code-first-development-with-entity-framework-4.aspx using Code-First approach.
Hope it helps!
Here my code for my Session class :
public class EFSession : ISession
{
DbContext _context;
public EFSession(DbContext context)
{
_context = context;
}
public void CommitChanges()
{
_context.SaveChanges();
}
public void Delete<T>(System.Linq.Expressions.Expression<Func<T, bool>> expression) where T : class, new()
{
var query = All<T>().Where(expression);
foreach (var item in query)
{
Delete(item);
}
}
public void Delete<T>(T item) where T : class, new()
{
_context.Set<T>().Remove(item);
}
public void DeleteAll<T>() where T : class, new()
{
var query = All<T>();
foreach (var item in query)
{
Delete(item);
}
}
public void Dispose()
{
_context.Dispose();
}
public T Single<T>(System.Linq.Expressions.Expression<Func<T, bool>> expression) where T : class, new()
{
return All<T>().FirstOrDefault(expression);
}
public IQueryable<T> All<T>() where T : class, new()
{
return _context.Set<T>().AsQueryable<T>();
}
public void Add<T>(T item) where T : class, new()
{
_context.Set<T>().Add(item);
}
public void Add<T>(IEnumerable<T> items) where T : class, new()
{
foreach (var item in items)
{
Add(item);
}
}
/// <summary>
/// Do not use this since we use EF4, just call CommitChanges() it does not do anything
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="item"></param>
public void Update<T>(T item) where T : class, new()
{
//nothing needed here
}
}
I've set up DI with Ninject in my ASP.NET MVC application like this
Bind<IRepository>().To<XmlDefaultRepository>().WhenInjectedInto(typeof(PageController)).WithConstructorArgument("contentType", ContentType.Page);
Bind<IRepository>().To<XmlDefaultRepository>().WhenInjectedInto(typeof(WidgetController)).WithConstructorArgument("contentType", ContentType.Page);
Bind<IRepository>().To<XmlDefaultRepository>().WhenInjectedInto(typeof(SectionController)).WithConstructorArgument("contentType", ContentType.Section);
Bind<IRepository>().To<XmlDefaultRepository>().WhenInjectedInto(typeof(WidgetZoneController)).WithConstructorArgument("contentType", ContentType.WidgetZone);
XmlDefaultRepository implements IRepository and it contains a constructor that takes contentType parameter which I use for persistance path generation.
Now I have a ServicesController which does not have a default type by itself - it is just a controller that provides JSON data (JSON actions) to consumers from jQuery.
This is how it looks now:
public class ServicesController : ContentController
{
public ActionResult ContentSlugs(string contentType, string q, int limit)
{
IRepository _repository = new XmlDefaultRepository(contentType); // this instantiation depends on contentType provided by JSON GET request at runtime and I want to somehow replace it with DI
return Json(_repository.GetSlugsForContentType(limit, q), JsonRequestBehavior.AllowGet);
}
}
And this is how other controllers look like (DI is done thru constructor injection here):
public class SectionController : ContentController
{
private IRepository ContentRepository;
public SectionController(IRepository repository)
{
ContentRepository = repository;
}
}
How can I get rid of "new XmlDefaultRepository(contentType)" dependency in ServicesController?
I've solved this problem by implementing method
_repository.GetSlugsForContentType(contentType, limit, q)
and creating a parameterless default constructor on XmlDefaultRepository implementation of IRepository.
This is the DI way of solving this issue with a Repository factory.
// ServicesController.cs
// ninject factory example, see IRepositoryFactory interface and its XmlRepositoryFactory implementation
[Inject]
public IRepositoryFactory RepositoryFactory
{
set
{
factory = value;
}
}
private IRepositoryFactory factory;
public ActionResult ContentSlugsThruFactory(string contentType, string q, int limit)
{
IRepository _repository = factory.Create(contentType);
return Json(_repository.GetSlugsForContentType(limit, q), JsonRequestBehavior.AllowGet);
}
// IRepositoryFactory.cs
public interface IRepositoryFactory
{
IRepository Create(string contentType);
}
// XmlRepositoryFactory.cs
public class XmlRepositoryFactory : IRepositoryFactory
{
public IRepository Create(string contentType)
{
return XmlDefaultRepository.Create(contentType);
}
}
// XmlDefaultRepository.cs
public static XmlDefaultRepository Create(ContentType contentType)
{
return new XmlDefaultRepository(contentType);
}
public static XmlDefaultRepository Create(string contentType)
{
return new XmlDefaultRepository(contentType);
}
// global.asax.cs
Bind<IRepositoryFactory>().To<XmlRepositoryFactory>().InSingletonScope();