I'm building pretty big application and I wonder how should I share the code between asp.net mvc website and standalone (self running) server application. I've got some idea how I should do this but I'm not sure if I'm doing this right. I've got Domain Entities, Services and Repositories that will be shared between asp.mvc app and server app. Services will perform transactions on multiple repositories using IDbTransaction (I can't use ORM, pure ado.net and mysql).
IDbContext.cs
public interface IDbContext : IDisposable
{
IUnitOfWork CreateUnitOfWork();
}
IDbContextFactory.cs
public interface IDbContextFactory
{
IDbContext Create();
}
IRepositoryFactory.cs
public interface IRepositoryFactory
{
T GetRepository<T>(IDbContext context, IUnitOfWork unitOfWork = null)
where T : class;
}
IUnitOfWork.cs
public interface IUnitOfWork : IDisposable
{
bool IsInTransaction { get; }
void BeginTransaction();
void BeginTransaction(IsolationLevel isolation);
void CommitTransaction();
void RollbackTransaction();
}
Now the MySql implementation
MysqlDbContext.cs
public class MysqlDbContext : IDbContext
{
#region Fields
private MySqlConnection _connection;
private bool _disposed;
#endregion
#region Constructor
public MysqlDbContext(MysqlConnectionFactory connectionFactory)
{
//Todo: create and open the connection
_connection = connectionFactory.Create();
if (_connection.State != ConnectionState.Open)
_connection.Open();
}
#endregion
public MySqlConnection Connection
{
get { return _connection; }
}
public IUnitOfWork CreateUnitOfWork()
{
return new MysqlUnitOfWork(_connection);
}
public void Dispose()
{
Dispose(true);
}
public void Dispose(bool disposing)
{
if (!disposing)
return;
/*
* Dispose resources
*/
if(_connection != null)
{
Console.WriteLine("Dispose connection!");
_connection.Dispose();
_connection = null;
}
//Set disposed
_disposed = true;
}
}
MysqlDbContextFactory.cs
public class MysqlDbContextFactory : IDbContextFactory
{
private MysqlConnectionFactory _connectionFactory;
public MysqlDbContextFactory(MysqlConnectionFactory connectionFactory)
{
_connectionFactory = connectionFactory;
}
public IDbContext Create()
{
return new MysqlDbContext(_connectionFactory);
}
}
MysqlRepositoryFactory.cs
public class MysqlRepositoryFactory : IRepositoryFactory
{
#region Constructor
public MysqlRepositoryFactory()
{
}
#endregion
public TRepository GetRepository<TRepository>(IDbContext context, IUnitOfWork unitOfWork = null)
where TRepository : class
{
if (typeof(TRepository) == typeof(IUserRepository))
return (new UserRepository(context, unitOfWork)) as TRepository;
return default(TRepository);
}
}
MysqlUnitOfWork.cs
public class MysqlUnitOfWork : IUnitOfWork
{
private readonly MySqlConnection _connection;
private MySqlTransaction _transaction;
private bool _disposed;
#region Constructor
public MysqlUnitOfWork(MySqlConnection connection)
{
if (connection.State != ConnectionState.Open)
throw new ApplicationException("Cannot begin transaction. Connection is not opened!");
_connection = connection;
}
#endregion
#region Properties
public bool IsInTransaction
{
get
{
if (_transaction != null)
return true;
return false;
}
}
public MySqlTransaction Transaction
{
get
{
return _transaction;
}
}
#endregion
public void BeginTransaction()
{
BeginTransaction(IsolationLevel.ReadCommitted);
}
public void BeginTransaction(IsolationLevel isolation)
{
if (_transaction != null)
throw new ApplicationException("Cannot begin a new transaction while an existing transaction is still running. Please commit or rollback the existing transaction before starting a new one");
_transaction = _connection.BeginTransaction(isolation);
}
public void CommitTransaction()
{
if (_transaction == null)
throw new ApplicationException("Cannot commit transaction while there is no transaction running");
_transaction.Commit();
}
public void RollbackTransaction()
{
if (_transaction == null)
throw new ApplicationException("Cannot rollback transaction while there is no transaction running");
_transaction.Rollback();
}
public void Dispose()
{
Dispose(true);
}
public void Dispose(bool disposing)
{
if (!disposing)
return;
if(_transaction != null)
{
_transaction.Dispose();
_transaction = null;
}
_disposed = true;
}
}
UserService.cs
public class UserService : IUserService
{
#region Fields
private readonly IDbContextFactory _dbContextFactory;
private readonly IRepositoryFactory _repositoryFactory;
#endregion
#region Constructor
public UserService(IDbContextFactory dbContextFactory, IRepositoryFactory repositoryFactory)
{
_dbContextFactory = dbContextFactory;
_repositoryFactory = repositoryFactory;
}
#endregion
public void Test()
{
using(var context = _dbContextFactory.Create())
{
var userRepository = _repositoryFactory.GetRepository<IUserRepository>(context);
userRepository.Create(new User
{
Username = "admin",
Password = "admin",
Email = "admin@bidit.com",
});
}
}
public void TestTransaction()
{
using(var context = _dbContextFactory.Create())
{
using(var uow = context.CreateUnitOfWork())
{
var userRepository = _repositoryFactory.GetRepository<IUserRepository>(context, uow);
//Begin new transaction (defualt isolation level: ReadCommited)
uow.BeginTransaction();
try
{
userRepository.Create(new User
{
Username = "rlydontknow",
Password = "12345",
Email = "rlydontknow@bidit.com",
});
//Commit transaction
uow.CommitTransaction();
}
catch
{
//Rollback transaction on error
uow.RollbackTransaction();
throw;
}
}
}
}
}
IDbContextFactory and IRepositoryFactory will be injected into service.
What do you think about my solution?