I have a unit of work with the repository pattern with simple injector implemented and I need to change my connection string dynamically. Currently the connection string is taken from the web config. I need the connection string be taken from the database.
So I will have a database with the ASP.Net Identity and the connections strings (and other configurations needed for my application) and then a database depending on the client.
My repositories and Unit of work are as follows.
public abstract class DataRepositoryBase<TEntity, TContext> : IDataRepository<TEntity>
where TEntity : class, IObjectStateEntity, new()
where TContext : class, IDbSimpleContextAsync
{
protected DataRepositoryBase(TContext context)
{
Context = context;
}
public virtual TContext Context { get; }
public IEnumerable<TEntity> Get()
{
return Context.Get<TEntity>();
}
public TEntity Get(object id)
{
return Context.Find<TEntity>(id);
}
}
public class SomeRepository : DataRepositoryBase<SomeObject, IContext>, ISomeRepository
{
public SomeRepository (IContext context) : base(context)
{
}
}
public abstract class UnitOfWorkBase : IUnitOfWork
{
private IDbSimpleContextAsync _dbContext;
protected UnitOfWorkBase(IDbSimpleContextAsync dbContext)
{
_dbContext = dbContext;
}
public int SaveChanges()
{
return _dbContext.SaveChanges();
}
public Task<int> SaveChangesAsync()
{
return _dbContext.SaveChangesAsync();
}
}
public class UnitOfWork : UnitOfWorkBase, IUnitOfWork
{
private ISomeRepository _someRepository
private readonly IContext _dbContext;
public UnitOfWork(IContext dbContext) : base(dbContext)
{
_dbContext = dbContext;
}
public ISomeRepository SomeRepository => _someRepository ?? (_someRepository = new SomeRepository(_dbContext));
}
public class BookingBusiness : IBookingBusiness
{
protected IAllotmentUnitOfWork UnitOfWork { get; }
public AllotmentBusinessBase(IUnitOfWork unitOfWork)
{
UnitOfWork = unitOfWork;
}
...
business methods here
...
}
So my idea is when reaching business, I query the configuration database for the connection string for the current user (the current unit of work injected points to that database), and somehow use that connection to instantiate a new unit of work for to connect to the correct database. Any ideas how i can achieve this using my current setup?
You should prevent injecting objects into the object graph that change based on runtime information. The question here is whether or not the connection string is still a constant value (won't change after the application started), or can change from request to request (for instance, when each user gets its own connection string).
In case the connection string is a constant, the solution is simple: Just request the connection string at start-up and use it indefinitely, just as you already are doing currently.
If your connection string isn't a constant value from the config file, but runtime information, it and its consuming DbContext should not be injected anymore directly into the object graph. Instead, you should define an abstraction that allows requesting the correct DbContext based on runtime information, such as logged in user.
So instead of injecting an IContext into SomeRepository and UnitOfWork, inject an IContextProvider, which can be defined as follows:
public interface IContextProvider
{
IContext Context { get; }
}
Your DataRepositoryBase can use IContextProvider as follows:
public IEnumerable<TEntity> Get()
{
return this.contextProvider.Context.Get<TEntity>();
}
public TEntity Get(object id)
{
return this.contextProvider.Context.Find<TEntity>(id);
}
The part left is to define an implementation for IContextProvider that can load the right connection string from the database, and create and cache a DbContext based on that connection string. Considering the limited amount of information given, this is only something you will know how to do.
Related
I have looked around on StackOverflow for a solution to my problem. Though I don't think this is a unique problem, I haven't been able to find a good solution.
In my WPF application, in my viewmodels, I need to call some services to return some data. These services get injected with UnitOfWork which in turn gets injected with the DbContext. This dbcontext that get injected into the UnitOfWork should differ based on some criteria.
I am having trouble doing the IoC container registrations the right way and injecting the right DbContext at runtime. So, if someone can please fill in the blanks (in the unity registrations as well as it's usage). I have some inline comments in the following code where I am in trouble and need help. Thanks.
If someone can replace my Registration code the right way and also educate me how to use it in my WPF ViewModel class, that would be truly great! Thanks.
One final note: If you find coding errors in this code, please don't start wondering how does this even compile? The code here is not my real code. To simplify things, I just wrote them up. But it does resemble very closely to my real app code.
public interface IDBContext{}
public interface IUnitOfWork{}
public interface ISomeEntityService{}
public interface IRepository<T> where T : class
{ T GetSingle( Expression<Func<T, bool>> predicate ); }
public class DBContext1 : IDBContext
{
public DBContext1(connString) : base(connString){}
}
public class DBContext2 : IDBContext
{
public DBContext2(connString) : base(connString){}
}
public class Repository<T> : IRepository<T> where T : class
{
private readonly IDBContext context;
private readonly IDbSet<T> dbSet;
public Repository(IDBContext ctx)
{
context = ctx;
dbSet = ((DbContext)context).Set<T>();
}
public T GetSingle( Expression<Func<T, bool>> predicate )
{
return ((DbContext)context).Set<T>().SingleOrDefault(predicate);
}
}
public class UnitOfWork : IUnitOfWork
{
IDBContext ctx;
private Dictionary<string, dynamic> repositories;
public UnitOfWork(IDBContext context)
{
ctx = context;
}
public IRepository<T> Repository<T>() where T : class
{
if (repositories == null)
repositories = new Dictionary<string, dynamic>();
var type = nameof(T);
if (repositories.ContainsKey(type))
return (IRepository<T>)repositories[type];
var repositoryType = typeof(Repository<>);
repositories.Add(type, Activator.CreateInstance(repositoryType.MakeGenericType(typeof(T)), ctx));
return repositories[type];
}
public int SaveChanges()
{
return ctx.SaveChanges();
}
}
public class MyUnityBootstrapper : UnityBootstrapper
{
protected override void ConfigureContainer()
{
Container.RegisterType<IDBContext, DBContext1>("Context1");
Container.RegisterType<IDBContext, DBContext2>("Context2");
Container.RegisterType(typeof(IRepository<>), typeof(Repository<>));
Container.RegisterType<IUnitOfWork, UnitOfWork>();
}
}
public class SomeEntityService : ISomeEntityService
{
private IUnitOfWork uow;
public ConsumerService( IUnitOfWork _uow )
{ uow = _uow; }
public SomeEntity GetSomeData( int id )
{
return uow.Repository<SomeEntity>().GetSingle( x => x.Id == id);
}
}
public class SomeViewModel : BindableBase
{
private readonly ISomeEntityService someService;
public SomeViewModel( ISomeEntityService _someService)
{
// when I call someService, I want to make sure it is using either
// DBContext1 or DBContext2 based on some condition I can set here.
// This is where I am totally stuck.
someService = _someService;
}
// get the repository instance with an id of 1000
someService.GetSomeData( 1000 );
}
/*
I could do something like this. But I am afraid, I am violating
two of the best practices recommendations.
1. I am creating a dependency to my IoC Container here.
2. I am using the container as a Service Locator
*/
public class SomeViewModel : BindableBase
{
private readonly ISomeEntityService someService;
public SomeViewModel()
{
var container = SomeHowGetTheContainer();
/*
1. Call Container.Resolve<IDBContext>(with the required context);
2. Use the retrieved context to inject into the UnitOfWork
3. Use the retrieved UnitOfWork to inject into the service
But that would be like throwing everything about best practices to the wind!
*/
someService = container.Resolve<ISomeEntityService>( /*do some magic here to get the right context*/)
}
// get the repository instance with an id of 1000
someService.GetSomeData( 1000 );
}
Add a factory like this that resolves your ISomeEntityService:
public MySomeEntityServiceFactory
{
public MySomeEntityServiceFactory( IUnityContainer container )
{
_container = container;
}
public ISomeEntityService CreateSomeEntityService( bool condition )
{
return _container.Resolve<ISomeEntityService>( condition ? "VariantA" : "VariantB" );
}
private readonly IUnityContainer _container;
}
and add two named bindings like:
_container.RegisterType<ISomeEntityService, SomeEntityService>( "VariantA", new InjectionConstructor( new ResolvedParameter<IDBContext>( "VariantA" ) ) );
_container.RegisterType<ISomeEntityService, SomeEntityService>( "VariantB", new InjectionConstructor( new ResolvedParameter<IDBContext>( "VariantB" ) ) );
For IUnitOfWork, you can add a similar factory that resolves the unit of work, and call it in SomeEntityService's constructor passing in the IDBContext...
Those factories are additional dependencies themselves, btw...
I'm trying to implement IoC in my windows form application. My choice fell on Simple Injector, because it's fast and lightweight. I also implement unit of work and repository pattern in my apps. Here is the structure:
DbContext:
public class MemberContext : DbContext
{
public MemberContext()
: base("Name=MemberContext")
{ }
public DbSet<Member> Members { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();\
}
}
Model:
public class Member
{
public int MemberID { get; set; }
public string Name { get; set; }
}
GenericRepository:
public abstract class GenericRepository<TEntity> : IGenericRepository<TEntity>
where TEntity : class
{
internal DbContext context;
internal DbSet<TEntity> dbSet;
public GenericRepository(DbContext context)
{
this.context = context;
this.dbSet = context.Set<TEntity>();
}
public virtual void Insert(TEntity entity)
{
dbSet.Add(entity);
}
}
MemberRepository:
public class MemberRepository : GenericRepository<Member>, IMemberRepository
{
public MemberRepository(DbContext context)
: base(context)
{ }
}
UnitOfWork:
public class UnitOfWork : IUnitOfWork
{
public DbContext context;
public UnitOfWork(DbContext context)
{
this.context = context;
}
public void SaveChanges()
{
context.SaveChanges();
}
private bool disposed = false;
protected virtual void Dispose(bool disposing)
{
if (!this.disposed)
{
if (disposing)
{
context.Dispose();
}
}
this.disposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
MemberService:
public class MemberService : IMemberService
{
private readonly IUnitOfWork unitOfWork;
private readonly IMemberRepository memberRepository;
public MemberService(IUnitOfWork unitOfWork, IMemberRepository memberRepository)
{
this.unitOfWork = unitOfWork;
this.memberRepository = memberRepository;
}
public void Save(Member member)
{
Save(new List<Member> { member });
}
public void Save(List<Member> members)
{
members.ForEach(m =>
{
if (m.MemberID == default(int))
{
memberRepository.Insert(m);
}
});
unitOfWork.SaveChanges();
}
}
In Member Form I only add a textbox to input member name and a button to save to database. This is the code in member form:
frmMember:
public partial class frmMember : Form
{
private readonly IMemberService memberService;
public frmMember(IMemberService memberService)
{
InitializeComponent();
this.memberService = memberService;
}
private void btnSave_Click(object sender, EventArgs e)
{
Member member = new Member();
member.Name = txtName.Text;
memberService.Save(member);
}
}
I implement the SimpleInjector (refer to http://simpleinjector.readthedocs.org/en/latest/windowsformsintegration.html) in Program.cs as seen in the code below:
static class Program
{
private static Container container;
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Bootstrap();
Application.Run(new frmMember((MemberService)container.GetInstance(typeof(IMemberService))));
}
private static void Bootstrap()
{
container = new Container();
container.RegisterSingle<IMemberRepository, MemberRepository>();
container.Register<IMemberService, MemberService>();
container.Register<DbContext, MemberContext>();
container.Register<IUnitOfWork, UnitOfWork>();
container.Verify();
}
}
When I run the program and add a member, it doesn't save to database. If I changed container.Register to container.RegisterSingle, it will save to database. From the documentation, RegisterSingle will make my class to be a Singleton. I can't using RegisterLifeTimeScope because it will generate an error
"The registered delegate for type IMemberService threw an exception. The IUnitOfWork is registered as 'Lifetime Scope' lifestyle, but the instance is requested outside the context of a Lifetime Scope"
1) How to use SimpleInjector in Windows Form with UnitOfWork & Repository pattern?
2) Do I implement the patterns correctly?
The problem you have is the difference in lifestyles between your service, repository, unitofwork and dbcontext.
Because the MemberRepository has a Singleton lifestyle, Simple Injector will create one instance which will be reused for the duration of the application, which could be days, even weeks or months with a WinForms application. The direct consequence from registering the MemberRepository as Singleton is that all dependencies of this class will become Singletons as well, no matter what lifestyle is used in the registration. This is a common problem called Captive Dependency.
As a side note: The diagnostic services of Simple Injector are able to spot this configuration mistake and will show/throw a Potential Lifestyle Mismatch warning.
So the MemberRepository is Singleton and has one and the same DbContext throughout the application lifetime. But the UnitOfWork, which has a dependency also on DbContext will receive a different instance of the DbContext, because the registration for DbContext is Transient. This context will, in your example, never save the newly created Member because this DbContext does not have any newly created Member, the member is created in a different DbContext.
When you change the registration of DbContext to RegisterSingleton it will start working, because now every service, class or whatever depending on DbContext will get the same instance.
But this is certainly not the solution because having one DbContext for the lifetime of the application will get you into trouble, as you probably already know. This is explained in great detail in this post.
The solution you need is using a Scoped instance of the DbContext, which you already tried. You are missing some information on how to use the lifetime scope feature of Simple Injector (and most of the other containers out there). When using a Scoped lifestyle there must be an active scope as the exception message clearly states. Starting a lifetime scope is pretty simple:
using (ThreadScopedLifestyle.BeginScope(container))
{
// all instances resolved within this scope
// with a ThreadScopedLifestyleLifestyle
// will be the same instance
}
You can read in detail here.
Changing the registrations to:
var container = new Container();
container.Options.DefaultScopedLifestyle = new ThreadScopedLifestyle();
container.Register<IMemberRepository, MemberRepository>(Lifestyle.Scoped);
container.Register<IMemberService, MemberService>(Lifestyle.Scoped);
container.Register<DbContext, MemberContext>(Lifestyle.Scoped);
container.Register<IUnitOfWork, UnitOfWork>(Lifestyle.Scoped);
and changing the code from btnSaveClick() to:
private void btnSave_Click(object sender, EventArgs e)
{
Member member = new Member();
member.Name = txtName.Text;
using (ThreadScopedLifestyle.BeginScope(container))
{
var memberService = container.GetInstance<IMemberService>();
memberService.Save(member);
}
}
is basically what you need.
But we have now introduced a new problem. We are now using the Service Locator anti pattern to get a Scoped instance of the IMemberService implementation. Therefore we need some infrastructural object which will handle this for us as a Cross-Cutting Concern in the application. A Decorator is a perfect way to implement this. See also here. This will look like:
public class ThreadScopedMemberServiceDecorator : IMemberService
{
private readonly Func<IMemberService> decorateeFactory;
private readonly Container container;
public ThreadScopedMemberServiceDecorator(Func<IMemberService> decorateeFactory,
Container container)
{
this.decorateeFactory = decorateeFactory;
this.container = container;
}
public void Save(List<Member> members)
{
using (ThreadScopedLifestyle.BeginScope(container))
{
IMemberService service = this.decorateeFactory.Invoke();
service.Save(members);
}
}
}
You now register this as a (Singleton) Decorator in the Simple Injector Container like this:
container.RegisterDecorator(
typeof(IMemberService),
typeof(ThreadScopedMemberServiceDecorator),
Lifestyle.Singleton);
The container will provide a class which depends on IMemberService with this ThreadScopedMemberServiceDecorator. In this the container will inject a Func<IMemberService> which, when invoked, will return an instance from the container using the configured lifestyle.
Adding this Decorator (and its registration) and changing the lifestyles will fix the issue from your example.
I expect however that your application will in the end have an IMemberService, IUserService, ICustomerService, etc... So you need a decorator for each and every IXXXService, not very DRY if you ask me. If all services will implement Save(List<T> items) you could consider creating an open generic interface:
public interface IService<T>
{
void Save(List<T> items);
}
public class MemberService : IService<Member>
{
// same code as before
}
You register all implementations in one line using Batch-Registration:
container.Register(typeof(IService<>),
new[] { Assembly.GetExecutingAssembly() },
Lifestyle.Scoped);
And you can wrap all these instances into a single open generic implementation of the above mentioned ThreadScopedServiceDecorator.
It would IMO even be better to use the command / handler pattern (you should really read the link!) for this type of work. In very short: In this pattern every use case is translated to a message object (a command) which is handled by a single command handler, which can be decorated by e.g. a SaveChangesCommandHandlerDecorator and a ThreadScopedCommandHandlerDecorator and LoggingDecorator and so on.
Your example would then look like:
public interface ICommandHandler<TCommand>
{
void Handle(TCommand command);
}
public class CreateMemberCommand
{
public string MemberName { get; set; }
}
With the following handlers:
public class CreateMemberCommandHandler : ICommandHandler<CreateMemberCommand>
{
//notice that the need for MemberRepository is zero IMO
private readonly IGenericRepository<Member> memberRepository;
public CreateMemberCommandHandler(IGenericRepository<Member> memberRepository)
{
this.memberRepository = memberRepository;
}
public void Handle(CreateMemberCommand command)
{
var member = new Member { Name = command.MemberName };
this.memberRepository.Insert(member);
}
}
public class SaveChangesCommandHandlerDecorator<TCommand>
: ICommandHandler<TCommand>
{
private ICommandHandler<TCommand> decoratee;
private DbContext db;
public SaveChangesCommandHandlerDecorator(
ICommandHandler<TCommand> decoratee, DbContext db)
{
this.decoratee = decoratee;
this.db = db;
}
public void Handle(TCommand command)
{
this.decoratee.Handle(command);
this.db.SaveChanges();
}
}
And the form can now depend on ICommandHandler<T>:
public partial class frmMember : Form
{
private readonly ICommandHandler<CreateMemberCommand> commandHandler;
public frmMember(ICommandHandler<CreateMemberCommand> commandHandler)
{
InitializeComponent();
this.commandHandler = commandHandler;
}
private void btnSave_Click(object sender, EventArgs e)
{
this.commandHandler.Handle(
new CreateMemberCommand { MemberName = txtName.Text });
}
}
This can all be registered as follows:
container.Register(typeof(IGenericRepository<>),
typeof(GenericRepository<>));
container.Register(typeof(ICommandHandler<>),
new[] { Assembly.GetExecutingAssembly() });
container.RegisterDecorator(typeof(ICommandHandler<>),
typeof(SaveChangesCommandHandlerDecorator<>));
container.RegisterDecorator(typeof(ICommandHandler<>),
typeof(ThreadScopedCommandHandlerDecorator<>),
Lifestyle.Singleton);
This design will remove the need for UnitOfWork and a (specific) service completely.
I'm trying to implement dependency injection but i know how to implement the interface and repository of classes then i don't know what shall i do.
This my sample:
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public string LastName { get; set; }
}
This is my interface:
public interface IUser
{
IEnumerable<User> GetUsers();
void AddUser(User user);
void EditUser(User user);
void DeleteUser(int id);
User UserGetById(int id);
void Save();
}
This is my repository:
public class UserRepsitory:IUser
{
private _Context _context;
public UserRepsitory(_Context _context)
{
this._context = _context;
}
public IEnumerable<User> GetUsers()
{
return _context.User.ToList();
}
public void AddUser(User user)
{
_context.User.Add(user);
}
public void EditUser(User user)
{
_context.Entry(user).State = System.Data.Entity.EntityState.Modified;
}
public User UserGetById(int id)
{
return _context.User.Find(id);
}
public void Save()
{
_context.SaveChanges();
}
public void DeleteUser(int id)
{
var Search = _context.User.Find(id);
_context.User.Remove(Search);
}
}
And one of method in controller:
private IUser userRepsitory;
public UsersController()
{
this.userRepsitory = new UserRepsitory(new _Context());
}
public UsersController(IUser UserRepository)
{
this.userRepsitory = UserRepository;
}
public ActionResult Index()
{
return View(userRepsitory.GetUsers());
}
What is the next step?
The first thing is, get rid of the default constructor where we are hard coding the initialization of UserRepository ! We will do that in the dependency injection way.
public UsersController : Controller
{
private readonly IUser userRepsitory;
public UsersController(IUser UserRepository)
{
this.userRepsitory = UserRepository;
}
public ActionResult Index()
{
return View(userRepsitory.GetUsers());
}
}
Now we need something to tell the MVC framework which version/implementation of IUser should be used when the code runs. you can use any dependency injection frameworks to do that. For example, If you are in MVC 6, you can use the inbuilt dependency injection framework to do that. So go to your Startup class and in your ConfigureServices method, you can map an interface to a concrete implementation.
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddTransient<IUser, UserRepository>();
}
}
If you are in a previous version of MVC, you may consider using any of the dependency injection frameworks available like Unity, Ninject etc.
It is pretty much same, you map an interface to a concrete implementation
Ninject
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<IUser>().To<UserRepository>();
}
You do not need to put the mapping in a cs file. You can define that in a config file. For example, when you use Unity you can do something like this in your config file (web config or an external config file for unity configuration)
Unity
<alias alias="IUser" type="YourNamespace.IUser, YourAssemblyName" />
<register type="IUser" mapTo="YourNamespace.UseRepository, YourAssemblyName">
In order to create and configure your project with Spring DI(Dependency Feature) you must configure beans.
Create an xml file (if its not there) and add references to bean
In this xml file, provide references to the classes you want to inject. Example:
<bean id="Name of the JAVA Class" class="the Full path of the JAVA class"/>
And in your class where you are supposed to call the referencing class(above), calling procedure would be like :
#Controller
public class MyController {
private full.path.of.my.class.named.MyJavaClass _class;
#Autowired
private MyController (full.path.of.my.class.MyJavaClass class)
{
this._class= class;
}
}
Now say if you a function in MyJavaClass
public int sum(int x, int y){
return x+y;
}
Then without creating object of MyJavaClass you can inject like the following in your controller:
_class.Sum(10,15);
YOU DO NOT CREATE AN INSTANCE OF THIS CLASS.
I'm working on an Asp.Net MVC 3 application using Fluent NHibernate. I'm just attempting to add an IoC container using StructureMap.
I have implemented a custom controller factory which uses StructureMap to create the controller and inject dependencies. Each controller constructor takes one or more services, which in turn take a DAO as constructor argument. Each DAO constructor takes an ISessionFactory.
For my StructureMap NHibernate registry I have the following:
internal class NHibernateRegistry : Registry
{
public NHibernateRegistry()
{
var connectionString = ConfigurationManager.ConnectionStrings["AppDb"].ConnectionString;
For<ISessionFactory>()
.Singleton()
.Use(x => new AppSessionFactory().GetSessionFactory(connectionString));
For<ISession>()
.HybridHttpOrThreadLocalScoped()
.Use(x => x.GetInstance<ISessionFactory>().OpenSession());
}
}
public class AppSessionFactory
{
public ISessionFactory GetSessionFactory(string connectionString)
{
return GetConfig(connectionString)
.BuildSessionFactory();
}
public static FluentConfiguration GetConfig(string connectionString)
{
return Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2005.ConnectionString(x => x.Is(connectionString)))
.Mappings(
x => x.FluentMappings.AddFromAssemblyOf<AppEntity>());
}
}
This all works fine for a single database and single session factory. However the application uses multiple databases.
What is the best way to handle this?
Registering multiple session factories is easy - the problem is selecting the right one when you need it. For example, let's say we have some sort of laboratory that has multiple databases. Each lab has a Location and multiple Samples for that location. We could have a SampleRepository that models that. Each Location has a unique key to identify it (e.g. "LabX", "LabY", "BlackMesa"). We can use that unique key as the name of the database connection string in the app.config file. In this example, we would have three connection strings in the app.config file. Here's a sample connectionStrings section:
<connectionStrings>
<add name="LabX" connectionString="Data Source=labx;User ID=someuser;Password=somepassword"/>
<add name="LabY" connectionString="Data Source=laby;User ID=someuser;Password=somepassword"/>
<add name="BlackMesa" connectionString="Data Source=blackmesa;User ID=freemang;Password=crowbar"/>
</connectionStrings>
Thus, we need to have a unique session factory for each connection string. Let's create a NamedSessionFactory that wraps ISessionFactory:
public interface INamedSessionFactory
{
public string Name { get; } // The name from the config file (e.g. "BlackMesa")
public ISessionFactory SessionFactory { get; }
}
public class NamedSessionFactory : INamedSessionFactory
{
public string Name { get; private set; }
public ISessionFactory SessionFactory { get; private set; }
public NamedSessionFactory(string name, ISessionFactory sessionFactory)
{
Name = name;
SessionFactory = sessionFactory;
}
}
Now we need to modify your AppSessionFactory a bit. First off, what you've created is a session factory factory - that's not quite what we're looking for. We want to give our factory a location and get a session out of it, not a session factory. Fluent NHibernate is what gives us session factories.
public interface IAppSessionFactory
{
ISession GetSessionForLocation(string locationKey);
}
The trick here is accept a list of INamedSessionFactory objects in the constructor. StructureMap should give us all of the INamedSessionFactory objects that we've registered. We'll get to registration in a second.
public class AppSessionFactory : IAppSessionFactory
{
private readonly IList<INamedSessionFactory> _factories;
public AppSessionFactory(IEnumerable<INamedSessionFactory factories)
{
_factories = new List<INamedSessionFactory>(factories);
}
This is where the magic happens. Given a location key, we run through our list of factories looking for one with the same name as locationKey, then ask it to open a session and return it to the caller.
public ISession GetSessionForLocation(string locationKey)
{
var sessionFactory = _factories.Where(x => x.Name == locationKey).Single();
return sessionFactory.OpenSession();
}
}
Now let's wire this all together.
internal class NHibernateRegistry : Registry
{
public NHibernateRegistry()
{
We're going to loop through all of the connection strings in our app.config file (there would be three of them in this example) and register an INamedSessionFactory object for each one.
foreach (ConnectionStringSettings location in ConfigurationManager.ConnectionStrings)
{
For<INamedSessionFactory>()
.Singleton()
.Use(x => new NamedSessionFactory(
location.Name,
GetSessionFactory(location.ConnectionString));
}
We also need to register IAppSessionFactory.
For<IAppSessionFactory>()
.Singleton()
.Use<AppSessionFactory>();
}
You'll notice that we've moved this logic out of the factory class... These are helper methods for creating session factories from Fluent NHibernate.
private static ISessionFactory GetSessionFactory(string connectionString)
{
return GetConfig(connectionString)
.BuildSessionFactory();
}
public static FluentConfiguration GetConfig(string connectionString)
{
return Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2005.ConnectionString(x => x.Is(connectionString)))
.Mappings(
x => x.FluentMappings.AddFromAssemblyOf<AppEntity>());
}
}
That should do it! Let's create a repository for getting at our samples...
public class SampleRepository
{
private readonly IAppSessionFactory _factory;
public SampleRepository(IAppSessionFactory factory)
{
_factory = factory;
}
public IEnumerable<Sample> GetSamplesForLocation(Location location)
{
using (ISession session = _factory.GetSessionForLocation(location.Key)
{
foreach (Sample sample in session.Query<Sample>())
yield return sample;
}
}
}
Now you can get a single instance of SampleRepository and use the GetSamplesForLocation method to pull samples from any of the three databases we have registered in app.config. Might want to avoid BlackMesa though. I understand there were problems there.
Are you sure this thing works? string ISessionFactory
public string ISessionFactory SessionFactory { get; private set; }
should this be
public interface INamedSessionFactory
{
ISessionFactory SessionFactory { get; set; }
string Name { get; }
}
public class NamedSessionFactory : INamedSessionFactory
{
public ISessionFactory SessionFactory { get; set; }
public string Name { get; private set; }
public NamedSessionFactory(string Name, ISessionFactory SessionFactory)
{
this.Name = Name;
this.SessionFactory = SessionFactory;
}
}
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.