UnitOfWork and DbContext: thread safety with DI - entity-framework

I'm working on a .NET Core 2.2 Console Application that hosts an IHostedService:
public class MqttClientHostedService : IHostedService, IDisposable
{
[...]
public MqttClientHostedService(
ILogger<MqttClientHostedService> logger,
IOptions<MqttClientConfiguration> mqttConfiguration,
IPositionService positionService)
{
this.logger = logger;
this.config = mqttConfiguration;
this.positionService = positionService;
}
public async Task StartAsync(CancellationToken cancellationToken)
{
mqttClient = new MqttFactory().CreateMqttClient();
mqttClient.Connected += async (s, e) => await MqttClient_Connected(s, e);
mqttClient.ApplicationMessageReceived +=
async (s, e) => await MqttClient_ApplicationMessageReceived(s, e);
await mqttClient.ConnectAsync(
new MqttClientOptionsBuilder()
.WithTcpServer(config.Value.Host, config.Value.Port).Build());
}
private async Task MqttClient_ApplicationMessageReceived(
object sender, MqttApplicationMessageReceivedEventArgs e)
{
string message = Encoding.UTF8.GetString(e.ApplicationMessage.Payload);
await positionService.HandleMessage(message);
}
[...]
}
This IPositionService is a manager that inspects the message and checks if it can be saved inside our database:
public class PositionService : IPositionService
{
[...]
public PositionService(
IUnitOfWork unitOfWork, ILogger<PositionService> logger)
{
this.unitOfWork = unitOfWork;
this.logger = logger;
}
public async Task HandleMessage(string message)
{
Entity entity = await unitOfWork.EntityRepository.GetByMessage(message);
[...]
await unitOfWork.EntityRepository.UpdateAsync(entity);
await unitOfWork.Save();
}
[...]
}
IUnitOfWork is a wrapper around Entity Framework Core DbContext (please don't judge me, I have reasons to do this):
public class UnitOfWork : IUnitOfWork
{
[...]
public UnitOfWork(MyContext myContext)
{
this.myContext = myContext;
EntityRepository = new EFRepository<Entity>(myContext);
}
public async Task Save()
{
await myContext.SaveChangesAsync();
}
}
EFRepository<T>, that implements IRepository<T> interface, is a wrapper around DbSet<T> (again, please don't judge me). No relevant code here.
Console Application's Program.cs is configured like that:
[...]
.ConfigureServices((hostContext, services) =>
{
services.AddDbContext<MyContext>(
c => c.UseSqlServer("[...]", options => options.UseNetTopologySuite()),
ServiceLifetime.Transient);
services.AddTransient<IPositionService, PositionService>();
services.AddTransient(typeof(IRepository<>), typeof(EFRepository<>));
services.AddTransient<IUnitOfWork, UnitOfWork>();
services.AddHostedService<MqttClientHostedService>();
[...]
});
Problem is that PositionService.HandleMessage is being called many times per second, and being that DbContext is not thread safe I get this error message:
A second operation started on this context before a previous operation
completed.
I solved this issue by removing IUnitOfWork from PositionService's dependencies, injecting instead an IServiceScopeFactory, and doing:
using (IServiceScope serviceScope = serviceScopeFactory.CreateScope())
{
IUnitOfWork unitOfWork = serviceScope.ServiceProvider.GetService<IUnitOfWork>();
[...]
}
This way works, but I don't like it. It seems like a trick, and I don't like the fact that my PositionService knows about Dependency Injection and has to deal with scopes.
My question is: there's a better way to solve this problem without touching my classes? Should I make the whole UnitOfWork thread safe? Or maybe create it by hand without using DI?

The source of the problem is that MyContext is held captive as a Captive Dependency in the following object graph:
MqttClientHostedService
-> PositionService
-> UnitOfWork
-> MyContext
All types in this graph are registered as Transient, but still, services that act as hosted service (e.g. your MqttClientHostedService) are resolved only once for the duration of the application and cached indefinately. This effectively makes them a singleton.
In other words, MyContext is accidentally kept alive by the single MqttClientHostedService and because multiple messages can come in in parallel, you have yourself a race condition.
The solution is to let each ApplicationMessageReceived event run in its own unique little bubble (a scope) and resolve a new IPositionService from within that bubble. For instance:
public class MqttClientHostedService : IHostedService, IDisposable
{
[...]
public MqttClientHostedService(
ILogger<MqttClientHostedService> logger,
IOptions<MqttClientConfiguration> mqttConfiguration,
IServiceProvider provider)
{
this.logger = logger;
this.config = mqttConfiguration;
this.provider = provider;
}
[...]
private async Task MqttClient_ApplicationMessageReceived(
object sender, MqttApplicationMessageReceivedEventArgs e)
{
using (var scope = provider.CreateScope())
{
positionService = scope.ServiceProvider
.GetRequiredService<IPositionService>();
string message = Encoding.UTF8.GetString(e.ApplicationMessage.Payload);
await positionService.HandleMessage(message);
}
}
[...]
}

Related

Using Microsoft.AspNetCore.Identity.MongoDB for Multi Tenancy. How do we inject dynamic Tenant into MongoDbContext

Does anyone know how we can inject context into User Manager > MongoDB serStore at runtime in .net core 2.0.
We cannot do this at startup due to the context being dynamic but the UserStore is not accessible and UserManager has too many variables to new up, and it is wrong. Are there any solutions?
public class UserStore<TUser> :
IUserPasswordStore<TUser>,
IUserRoleStore<TUser>,
IUserLoginStore<TUser>,
IUserSecurityStampStore<TUser>,
IUserEmailStore<TUser>,
IUserClaimStore<TUser>,
IUserPhoneNumberStore<TUser>,
IUserTwoFactorStore<TUser>,
IUserLockoutStore<TUser>,
IQueryableUserStore<TUser>,
IUserAuthenticationTokenStore<TUser>
where TUser : IdentityUser
{
private readonly IMongoCollection<TUser> _Users;
//THIS IS WHERE WE WANT TO INJECT THE users AT RUNTIME
public UserStore(IMongoCollection<TUser> users)
{
_Users = users;
}
public virtual void Dispose()
{
// no need to dispose of anything, mongodb handles connection pooling automatically
}
public virtual async Task<IdentityResult> CreateAsync(TUser user, CancellationToken token)
{
await _Users.InsertOneAsync(user, cancellationToken: token);
return IdentityResult.Success;
}
unfortunately users is null at startup, and should be as the tenant has not been created at that point.
We have also been using the saaskit.Multitenancy and just can't find a solution.
Any help would be much appreciated.
Thanks
i think u need a generic repository to act as a wrapper for IMongoCollection then inject the repository inside controllers
public class Repository<T>
{
public IMongoCollection<T> Collection { get; private set; }
public Repository(IDbFactory dbFactory)
{
MongoClient client = new MongoClient("ur connection string");
this.Collection = client.GetDatabase("db").GetCollection<T>(typeof(T).Name);
}
public T Find(Expression<Func<T, bool>> filter)
{
return this.Collection.AsQueryable<T>().FirstOrDefault<T>(filter);
}
public async Task<T> FindAsync(Expression<Func<T, bool>> filter)
{
return await this.Collection.AsQueryable<T>().FirstOrDefaultAsync<T>(filter);
}
// here add more methods
}
then register the dependency as below inside Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddTransient(typeof(IRepository<>), typeof(Repository<>));
services.AddMvc();
}
finally inside controllers u inject the generic repository, also dont forget to Implement the IDisopsible in genereic repository
public class ProductController : Controller
{
private readonly IRepository<Product> _productRepository = null;
public ProductController(IRepository<Product> productRepository)
{
this._productRepository = productRepository;
}
}

one transaction for multiple contexts in integration tests on TestInitialize

I am writing integration tests and I want to use transaction scope.
We use EF and Repositories with Contexts.
If I have one Repository and once Context then it would look like this:
[TestInitialize]
public void RuleEngineTestsStart() {
customContext = new CustomContext();
transaction = customContext.Database.BeginTransaction();
repo = new CustomRepository(customContext);
// I need to make this context to work in the same transaction as above
anotherContext = new AnotherContext();
anotherRepo = new AnotherRepository(anotherContext);
}
At the end of tests (TestCleanup) I would like to transaction.Rollback(); everything.
I want to have the same transaction for all repositories that work with different contexts, is it possible? How to create transaction and 'send' it to all three contexts?
Please, to do not to use one Context for all repositories, it is not possible due to reasons (we want to have each context with its own DbSets later to be used within microservices).
Edit
In comments I was asked to include more code, however, I think is not necessary to answer my question.
customContext = new CustomContext();
repo = new CustomRepository(customContext);
customContext2 = new CustomContext2();
otherRepository = new CustomRepository2(customContext2);
// class to be tested needs both repositories
ToBeTestedClass cl = new ToBeTestedClass(customRepository, otherRepository);
// "BASE" interface
public interface IRepository<TEntity> where TEntity : class
{
TEntity GetById(long id);
IEnumerable<TEntity> GetByFilter(Expression<Func<TEntity, bool>> predicate);
TEntity GetSingleByFilter(Expression<Func<TEntity, bool>> filter);
void Insert(TEntity entity);
void Delete(long id);
void Update(TEntity entity);
...
}
// BASE CLASS
public class Repository<TEntity> : IRepository<TEntity> where TEntity : class
{
protected readonly DbContext _context;
protected readonly DbSet<TEntity> _dbSet;
public Repository(ColldeskDbContext context)
{
_context = context;
_dbSet = context.Set<TEntity>();
}
// GetSingle, GetAll, Insert, Update etc.
}
// CustomRepository (other Repositories are similar, with custom methods)
public interface ICustomRepository : IRepository<CusotmData>
{
// some specific methods that are not in Base class
}
public class CustomRepository: Repository<CustomData>, ICustomRepository
{
public CustomRepository(CustomContext context) : base(context)
{
}
// custom methods that are specific for given context
}
// Contexts - each context consists of its one DbSets
Don't use dbContext.SaveChanges() in your repositories. Use ONE dbContext when creating repositories. Sample:
using ( var db = new YourDbContext() )
{
// Create and begin transaction
using ( var transaction = db.Database.BeginTransaction() )
{
try
{
// ONE dbContext for all repositories
var firstRepo = new Custom1Repository(db);
var secondRepo = new Custom2Repository(db);
City city = new City { Description = "My city" };
Street street = new Street { Description = "My street", City = city};
firstRepo.Insert(city);
secondRepo.Insert(street);
// Save all your changes and after that commit transaction
db.SaveChanges();
transaction.Commit();
}
catch ( Exception ec)
{
transaction.Rollback();
}
}
}
Doing like this your repositories becomes just wrappers over DbSet<TEntity>
I have figured out that I can simply use TransactionScope like this:
private TransactionScope _scope;
[TestInitialize]
public void TestInitialize()
{
_scope = new TransactionScope();
}
[TestCleanup]
public void TestCleanup()
{
_scope.Dispose();
}
And then each Context would be running within this TransactionScope.

Passing connection string to Entity framework at runt time for each call

My Entity framework context is as following
public partial class MyContext : DbContext, IMyContext
{
static MyContext()
{
System.Data.Entity.Database.SetInitializer<MyContext>(null);
}
public MyContext()
: base("Name=MyContext")
{
}
I am resolving it through autofac in the following way
builder.RegisterType(typeof(MainContext)).As(typeof(DbContext)).InstancePerLifetimeScope();
builder.RegisterType<MainContext>().As<IMainContext>().InstancePerRequest();
This db context gets called in repository layer
#region Fields
private readonly IMyContext _context;
#endregion
#region Constructors and Destructors
public EmployeeRepository(IMyContext context)
{
_context = context;
}
#endregion
public void Create(Employee emp)
{
this._context.Employee.Add(emp);
}
Now my issue is , I want to set the connection string dynamically per call. The connection string will be passed through a webapi which i want to pass on to this context. Can anyone help me how can i do that? I am confused about autofac here. Secondly how can i make sure each call sets connection string and does not cache it.
You can use a factory that will build the context and set the connectionstring for you.
public interface IContextFactory
{
IContext GetInstance();
}
public class MyContextFactory : IContextFactory
{
public IContext GetInstance()
{
String connectionString = this.GetConnectionString(HttpContext.Current);
return new MyContext(connectionString);
}
private String GetConnectionString(HttpContext context)
{
// do what you want
}
}
builder.RegisterType<MyContextFactory>()
.As<IContextFactory>()
.InstancePerRequest();
builder.Register(c => c.Resolve<IContextFactory>().GetInstance())
.As<IContext>()
.InstancePerRequest();
If you can't get connectionstring based on HttpContext, you can change contextFactory implementation to expect initialization by WebAPI before creating the instance. For example :
public interface IContextFactory
{
IContext GetInstance();
void Initialize(String connectionString);
}
public class MyContextFactory : IContextFactory
{
private String _connectionString;
public void Initialize(String connectionString)
{
this._connectionString = connectionString;
}
public IContext GetInstance()
{
if (this._connectionString == null)
{
throw new Exception("connectionString not initialized");
}
return new MyContext(this._connectionString);
}
}
At the beginning of your web API call (through attribute for example), you can call the Initialize method. Because the factory is InstancePerRequest you will have one instance for the duration of the request.
By the way, I'm not sure to understand this registration
builder.RegisterType(typeof(MainContext)).As(typeof(DbContext)).InstancePerLifetimeScope();
builder.RegisterType<MainContext>().As<IMainContext>().InstancePerRequest();
It looks buggy because you will have 2 different registration of the same type and not for the same scope, is it intended ? Furthermore, it doesn't sound a good idea to register a DbContext, do you need this registration ?
The following registration looks better :
builder.RegisterType<MainContext>()
.As<IMainContext>()
.As<DbContext>()
.InstancePerRequest();

How to structure unitofwork / service layer / repository, so that they work with DI (Unity) and Moq for Unit Testing

I have an MVC app (EF6, SQL Server CE 4), that I recently refactored to add a UnitOfWork class and a service layer (so that I could utilise a single DbContext per request, and conduct transactions successfully).
Previously, I was using Unity to inject the repositories into the controller. My unit tests (for the controllers) were simple to setup - I just mocked each repository, and passed those into the controller constructor.
After refactoring, I now use Unity to inject the Service Layer (to the controller) and UnitOfWork (into the Service Layer). The Service Layer now instantiates each repository, by passing the UnitOfWork.DbContext to the repository's constructor.
In my Unit Tests, I am attempting to mock the UnitOfWork, and the ServiceLayer (and pass the mocked UnitOfWork object into the ServiceLayer's constructor). However, the tests fail, saying "TestFixtureSetup failed in ControllerTest".
I assume it's due to how I'm attempting to pass the UnitOfWork mock into the ServiceLayer mock, so would appreciate any guidance on how to do this correctly.
Relevant code snippets below.
UnitOfWork
public interface IUnitOfWork:IDisposable
{
void Save();
IDSMContext Context { get; }
}
public class UnitOfWork : IUnitOfWork, IDisposable
{
private IDSMContext _context;
public UnitOfWork()
{
_context = new IDSMContext();
}
public IDSMContext Context
{
get {return _context;}
}
public void Save()
{
_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);
}
}
Service Layer
public interface IService
{
// Repositories
IUserRepository Users { get; }
IUserTeamRepository UserTeams { get; }
IPlayerRepository Players { get; }
IGameRepository Games { get; }
IUserTeam_PlayerRepository UserTeamPlayers { get; }
void Save();
}
public class Service: IService, IDisposable
{
private IUnitOfWork _unitOfWork;
private IUserRepository _userRepository;
private IUserTeamRepository _userTeamRepository;
private IPlayerRepository _playerRepository;
private IGameRepository _gameRepository;
private IUserTeam_PlayerRepository _userTeamPlayerRepository;
public Service(IUnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;
initialiseRepos();
}
private void initialiseRepos(){
_userRepository = _userRepository ?? new UserRepository(_unitOfWork.Context);
_userTeamRepository = _userTeamRepository ?? new UserTeamRepository(_unitOfWork.Context);
_playerRepository = _playerRepository ?? new PlayerRepository(_unitOfWork.Context);
_gameRepository = _gameRepository ?? new GameRepository(_unitOfWork.Context);
_userTeamPlayerRepository = _userTeamPlayerRepository ?? new UserTeam_PlayerRepository(_unitOfWork.Context);
}
public IUserRepository Users { get { return _userRepository; } }
public IUserTeamRepository UserTeams { get { return _userTeamRepository; } }
public IPlayerRepository Players { get { return _playerRepository; } }
public IGameRepository Games { get { return _gameRepository; } }
public IUserTeam_PlayerRepository UserTeamPlayers { get { return _userTeamPlayerRepository; } }
public void Save()
{
_unitOfWork.Save();
}
Unity Container Instance Setup
Instance.RegisterType<IService, Service>(new PerThreadLifetimeManager())
.RegisterType<IUnitOfWork, UnitOfWork>();
Controller Constructor
public GameController(IService service)
{
_service = service;
}
Test Constructor
_mockUnitOfWork = new Mock<IUnitOfWork>();
_mockServiceLayer = new Mock<IService>(_mockUnitOfWork.Object); //this line fails
Test Controller Method
GameController Controller = new GameController(_mockServiceLayer.Object);
If you want to test methods of GameController you just need to mock/stub the dependencies of that class. Just do this:
_mockServiceLayer = new Mock<IService>();
_controller = new GameController(_mockServiceLayer.Object);
When you are testing the Controller, you shouldn't worry about the dependencies of the service. UnitOfWork is never exposed outside your service, so don't worry about it when testing the controller. On your tests you may now setup expectations of methods called on your service, like verifying that Save was called once (If you were testing the service, then you would worry about the IService.Save calling Save on a mock of the IUnitOfWork!):
_mockServiceLayer.Verify(s=> s.Save(), Times.Once());
The problem you will find is that your service class is not abstracting the controller from the repositories, as your controller will get the repositories via the properties in IService and query directly the repositories. So if you want to test your controller methods, you will still need to mock the repositories, doing something like:
//Initialization before each test:
_mockUserRepo = new Mock<IUserRepository>();
//...other repositories
_mockServiceLayer = new Mock<IService>();
_mockServiceLayer.Setup(s => s.Users).Returns(_mockUserRepo.Object);
//... setup properties in IService for other repositories
_controller = new GameController(_mockServiceLayer.Object);
//In some test:
var user = new User();
_mockUserRepo.Setup(s => s.Get(123)).Returns(user);
call some controller method and make sure returned model is "user"
This way you may find yourself configuring the expectations and data returned by a few repositories and the UnityOfWork, just for testing the methods in the Controller! Not to mention that your Controller class effectively depends on your repositories, not just on the service.
Another approach would be if your service class contains higher level methods like GetUser, CreateUser or AddUserToTeam (likely having multiple services with closely related methods). The service would then shield the controller from retrieving/sending data to the repositories and using the UnitOfWork.
That way in your tests you would only need to mock IService.
For example a test for a typical "GET" action may look like:
//Arrange
var user = new User();
_mockServiceLayer.Setup(s => s.GetUser(123)).Returns(user);
//Act
var viewResult = _controller.GetUser(123) as ViewResult;
//Assert
Assert.AreEqual(user, viewResult.Model);
Hopefully this will help clarifying things a bit!
In the line that fails you are mocking the IService which does not have a constructor, so passing it args will cause it to fail. Since you are only trying to unit test the controller, you should change the line to this:
_mockServiceLayer = new Mock<IService>();
and then specify the the behaviors you want using _mockServiceLayer.Setup(...). Remember your interface doesn't know anything about your unit of work so you do not need to mock the unit of work.
If you actually want to test the controller and service layer together then you would do something like this:
_mockUnitOfWork = new Mock<IUnitOfWork>();
var serviceLayer = new Service(_mockUnitOfWork.Object);
var controller = new GameController(serviceLayer);
You would probably be better off unit testing the controllers and the serviceLayer separately, each time mocking the layer below.

What's DataService Best practice using Entity Framework and Repository and UnitOfWork Patterns

I'm using EF and MVVM pattern. My question is about the Data Access Layer. in DAL I have the following classes:
MyObjectContext which is technically the standard ObjectContext now, but some Unit-of-work methods will be added to it later.
Repository<TModel> which handles the most needed queries (such as Add, GetAll, ...) on different ObjectSets.
A bunch of DataServices which make use of repositories to provide a higher level of data access for Core.
The project I'm working on is a business application with about 100 EntitySets so far, and there are times when a single interaction of a user can involve up to 20 different EntitySets (updating most of them). I currently add .Include(params string[]) to my queries to prevent ObjectContextDisposedException but it doesn't seem to be a reliable solution.
The question is should I create an instance of MyObjectContext (and therefore Repository) in each of DataService methods (like the following codes, it seems to me that the ability of Unit of work would be useless in this case) or should I create it outside of DataService and pass it to the DataServices through their constructors (or directly to each of the DataService methods) to handle a bunch of database actions (different tables and queries) together. And how?
Here's what MyObjectContext looks like:
public class MyObjectContext : ObjectContext, IUnitOfWork
{
public MyObjectContext()
: base("name=EdmContainer", "EdmContainer")
{
ContextOptions.LazyLoadingEnabled = true;
}
#region IUnitOfWork Members
public void Commit()
{
SaveChanges();
}
#endregion
}
This is how Repository looks like:
public class Repository<TModel>
{
private readonly SoheilEdmContext _context;
public Repository(IUnitOfWork unitOfWork)
{
if (unitOfWork == null)
throw new ArgumentNullException("unitOfWork");
_context = unitOfWork as SoheilEdmContext;
}
public TModel FirstOrDefault(Expression<Func<TModel, bool>> where)
{
return _context.CreateObjectSet<TModel>().FirstOrDefault(where);
}
public void Add(TModel entity)
{
_context.CreateObjectSet<TModel>().AddObject(entity);
}
...
}
And this is how a common DataService looks like:
public class JobDataService : IDataService<Job>
{
#region IDataService<Job> Members
public Job GetSingle(int id)
{
Job model = null;
using (var context = new MyObjectContext())
{
var repos = new Repository<Job>(context);
model = repos.FirstOrDefault(x => x.Id == id);
}
return model;
}
public IEnumerable<Job> GetAll()
{
using (var context = new MyObjectContext())
{
var repos = new Repository<Job>(context);
var models = repos.GetAll();
return models;
}
}
public IEnumerable<Job> GetActives()
{
throw new NotImplementedException();
}
public int AddModel(Job model)
{
using (var context = new MyObjectContext())
{
var repos = new Repository<Job>(context);
repos.Add(model);
context.SaveChanges();
}
}
public void UpdateModel(Job model)
{
throw new NotImplementedException();
}
public void DeleteModel(Job model)
{
using (var context = new MyObjectContext())
{
var repos = new Repository<Job>(context);
var model = repos.FirstOrDefault(x => x.Id == model.Id);
if (model == null) return;
repos.Delete(model);
context.SaveChanges();
}
}
#endregion
}
Any kind of idea or insight would be appreciated.
You can create an instance of MyObjectContext in each service, like JobDataService, however, it makes your code messy and it is hard to maintain. Create instance of MyObjectContext outside of DataService is better. What you have now, if you have 100 EntitySets, you have to create 100 DataServices. That is because the use of "Repository Pattern" and "UnitOfWork" here is not efficient. I would suggest doing the following:
ObjectContext
public class MyObjectContext : ObjectContext
{
public MyObjectContext() : base("name=EdmContainer", "EdmContainer")
{
ContextOptions.LazyLoadingEnabled = true;
}
#region IUnitOfWork Members
public void Commit()
{
SaveChanges();
}
#endregion
}
Generic Repository
public interface IRepository<TModel> where TModel : class
{
void Add(TModel entity);
IEnumerable<TModel> GetAll();
// Do some more implement
}
public class Repository<TModel> : IRepository<TModel> where TModel : class
{
private readonly ObjectContext _context;
public Repository(ObjectContext context)
{
_context = context;
}
public virtual void Add(TModel entity)
{
_context.CreateObjectSet<TModel>().AddObject(entity);
}
public virtual IEnumerable<TModel> GetAll()
{
return _context.CreateObjectSet<TModel>();
}
}
UnitOfWork
public interface IUnitOfWork : IDisposable
{
IRepository<Job> Jobs { get; }
IRepository<User> Users { get;}
void Commit();
}
public class UnitOfWork : IUnitOfWork
{
private readonly SoheilEdmContext _context;
private readonly IRepository<Job> _jobRepository;
private readonly IRepository<User> _userRepository;
public UnitOfWork(SoheilEdmContext context)
{
_context = context;
_jobRepository = new Repository<Job>(_context);
_userRepository = new Repository<User>(_context);
}
public IRepository<Job> Jobs{get { return _jobRepository; }}
public IRepository<User> Users{get { return _userRepository; }}
public void Commit(){_context.Commit();}
public void Dispose()
{
if (_context != null)
{
_context.Dispose();
}
GC.SuppressFinalize(this);
}
JodDataSerivce
public interface IDataService
{
IEnumerable<Job> GetAll();
}
public class DataService : IDataService
{
private readonly IUnitOfWork _unitOfWork;
public DataService(IUnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;
}
public IEnumerable<Job> GetAll()
{
return _unitOfWork.Jobs.GetAll();
}
}
Here I used interface for implementing everything, if you want to do the same, you need to use IoC Container. I used the "Simple Injector", you can find it here:
Simple Injector
One more suggestion, if you feel like you have too many I/O operations to implement, like database access, querying data, etc., you should consider using Asynchronous. Below is a good video on Asynchronous.
How to Build ASP.NET Web Applications Using Async