What is it?
It’s a light-weight implementation of UnitOfWork pattern. I found all published solution aren’t really transactional & mix between the role of Repository & the role of the UnitOfWork itself. Recently, Rob Conery explained this in a very good way here. He offered other solutions to avoid this broken non-transactional UoW kind of implementation.
Why I did this?
I didn’t build this just because I needed to build a better implementation. I was refactoring a legacy web application to be ready to be published on Windows Azure. The problem was that the application had an architectural anti-pattern, Transactional Integration. It was built depending on heavy usage of TransactionScope almost everywhere. Scopes were its unit of work to integrate any two components or types, not only services! Since that this project has a limited time, so building from scratch with proper architecture & design isn’t an option. So I needed to find a new way to define unit of work that can accommodate both business & database transactions/layers. At the same time, it was built with Linq2SQL! Decision was made to move Entity Framework 6 since that we are going to use Windows Azure SQL Databases (SQL Azure). We needed to benefit from its new Connection Resilience feature. At the same time, EF6 + SqlAzureExecutionStrategy doesn’t accept the use of TransactionScope or any form of user provided transaction, list of limitation here. Which means clearing all TransactionScope statements from solution otherwise it won’t work on cloud. Because of the design of the application, there’s a need to share a UoW between different components so they can run in context of a single transaction without wrapping them in one TransactionScope.
What is in ReliableUnitOfWork.SqlAzure?
This the solution for my problem & I think it can help in other different scenarios when you need to share different component in one transaction. The solution is based on wrapping a DbContext instance in a UnitOfWork instance and provides generic way of passing this it to different players who are going to share in this unit until it disposed. There are 3 ways to make use of this.
Before talking about this way, what are changes do you need to implement in your current EF-based solution to benefit from this implementation? Almost nothing serious, you need to inherit from type UnitDbContext. I’ll use snippets from Contoso University, the Microsoft sample for MVC5 & EF6. It needs long time to convert the whole solution to use this implementation so I’ll just try to explain how anyone can achieve this.
public class SchoolContext : UnitDbContext
{
public DbSet<Course> Courses { get; set; }
public DbSet<Department> Departments { get; set; }
public DbSet<Enrollment> Enrollments { get; set; }
public DbSet<Instructor> Instructors { get; set; }
public DbSet<Student> Students { get; set; }
public DbSet<Person> People { get; set; }
public DbSet<OfficeAssignment> OfficeAssignments { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
modelBuilder.Entity<Course>()
.HasMany(c => c.Instructors).WithMany(i => i.Courses)
.Map(t => t.MapLeftKey("CourseID")
.MapRightKey("InstructorID")
.ToTable("CourseInstructor"));
modelBuilder.Entity<Department>().MapToStoredProcedures();
}
}
Way One, using UnitOfWorkFactory directly
The first way is the simplest that almost doesn't give something new. It enables you to create a new UoW where you're going to directly access the DbContext inside it to perform anything you need. So it's just a mechanism to get a fresh
DbContext when you need it & dispose it immediately after using it.
// GET: /Department/Create
public ActionResult Create()
{
using (var uow = _unitOfWorkFactory.StartNew())
{
ViewBag.InstructorID = new SelectList(uow.DbContext.Instructors,
"ID", "FullName");
}
return View();
}
The above example makes use of UnitOfWorkFactory directly with shortest overload of StartNew().
You may think that for one of the controllers that has many Read-Only Action, it could be suitable to create a single UoW in controller’s constructor & dispose it while disposing the controller. Just make sure you name it differently, like _readOnlyUnitOfWork, so you don’t use it to persist something unintentionally. Later, I’m thinking to add the feature of to create ReadOnlyUnitOfWork that overrides SaveChanges() & SaveChangesAsync() to throw exception when someone unintentionally call them.
To see how you can save changes, see the next snippet. It's just straight forward.
// POST: /Department/Create
// To protect from overposting attacks, please enable the specific properties
// you want to bind to, for more details see
// http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Create(
[Bind(Include = "DepartmentID,Name,Budget,StartDate,InstructorID")]
Department department)
{
using (var uow = _unitOfWorkFactory.StartNew())
{
if (ModelState.IsValid)
{
uow.DbContext.Departments.Add(department);
await uow.DbContext.SaveChangesAsync();
return RedirectToAction("Index");
}
ViewBag.InstructorID = new SelectList(
uow.DbContext.Instructors, "ID", "FullName", department.InstructorID);
return View(department);
}
}
Way Two, using UnitOfWorkFactory with Repository & DomainService abstract classes.
In other scenarios, you may need to build your own repositories & aggregates & domain services, if you have a rich domain. Let’s say we need to build StudentRepository & CourseRepository & DepartementRepository & CatalogueService. The CatalogueService will consume mentioned repositories to perform different tasks, so you need a way to share the DbContext between them & make sure to SaveChanges() in a single Transaction.
The implementation has the concept of UnitOfWorkPlayer, and also Repository which inherits from UnitOfWorkPlayer. When create a new UoW using StartNew() method in UnitOfWorkFactory you can pass all CatalogueService dependencies so you get a UoW that's aware of all of them & take their changes via a single instance of UnitDbContext. Types that inherits from UnitOfWorkPlayer are required to implement one method, the HandlePlayerJoinedUnit(). What for? if this type has also a dependency on types that inherit from UnitOfWorkPlayer it'll also join the same UoW. So the player isn't a must to be a repository only. It could be another type, like RiskCalculator, that needs access to UoW and/or other repositories to perform some task as part of a wider context.
I believe it's getting more complex talking about it & a short sample should be clearer than talk.
At this point, I'll fake up some example to show how to write the code until I got more time to write a complete scenario. Initially, this is how we can define skeleton of our repositories.
public interface IStudentRepository : IRepository<SchoolContext>
{
}
public interface ICourseRepository : IRepository<SchoolContext>
{
}
public interface IDepartmentRepository : IRepository<SchoolContext>
{
}
public class StudentRepository : Repository<SchoolContext>, IStudentRepository
{
}
public class CourseRepository : Repository<SchoolContext>, ICourseRepository
{
}
public class DepartmentRepository : Repository<SchoolContext>, IDepartmentRepository
{
}
The skeleton for the CatalogService should depend on these repositories and can be defined as follows.
public interface ICatalogueService : IDomainService<SchoolContext>
{
}
public class CatalogueService : DomainService<SchoolContext>, ICatalogueService
{
private readonly IStudentRepository _studentRepository;
private readonly ICourseRepository _courseRepository;
private readonly IDepartmentRepository _departmentRepository;
protected CatalogueService(IUnitOfWorkFactory<SchoolContext> uowFactory,
IStudentRepository studentRepository,
ICourseRepository courseRepository,
IDepartmentRepository departmentRepository)
: base(uowFactory, studentRepository, courseRepository, departmentRepository)
{
_studentRepository = studentRepository;
_courseRepository = courseRepository;
_departmentRepository = departmentRepository;
}
public void SomeMethod()
{
using (var uow = StartNewUnit())
{
// here you can call _studentRepository, _courseRepository,
// and _departmentRepository to perform required job in a single UoW.
uow.DbContext.SaveChanges();
}
}
}
Summary
That was long I believe & I hope it's not too vague :)
I ripped this, without tests & examples, from a real-world solution after I read Rob's article that I liked too much & I hope that this implementation avoided some of mentioned pitfalls & hopefully doesn't introduced any new pitfalls :) Later on, as soon as I have a chance, I'll add a complete example of how it works for me. What's available online now is GitHub repository
here and a NuGet package
here.