I am using EF Core 1.0 (previously known ad EF7) and ASP.NET Core 1.0 (previously known as ASP.NET 5) for a RESTful API.
I\'d like to have some unit of work scoped t
As per Entity Framework Core 1.0 DbContext not scoped to http request I could not use a middleware to achieve this because the instance of DbContext that the middleware gets injected is not the same as the DbContext during MVC execution (in my controllers, or repositories).
I had to go with a similar approach to save the changes in DbContext after the controller's action execution using a Global Filter. There is no official documentation yet about filters in MVC 6 so if anybody is interested on this solution see below the filter and the way I make this filter global so that it executes before any controller's action.
public class UnitOfWorkFilter : ActionFilterAttribute
{
private readonly MyDbContext _dbContext;
private readonly ILogger _logger;
public UnitOfWorkFilter(MyDbContext dbContext, ILoggerFactory loggerFactory)
{
_dbContext = dbContext;
_logger = loggerFactory.CreateLogger();
}
public override async Task OnActionExecutionAsync(ActionExecutingContext executingContext, ActionExecutionDelegate next)
{
var executedContext = await next.Invoke(); //to wait until the controller's action finalizes in case there was an error
if (executedContext.Exception == null)
{
_logger.LogInformation("Saving changes for unit of work");
await _dbContext.SaveChangesAsync();
}
else
{
_logger.LogInformation("Avoid to save changes for unit of work due an exception");
}
}
}
and the filter gets plugged into my MVC at Startup.cs
when configuring MVC.
public void ConfigureServices(IServiceCollection services)
{
//..
//Entity Framework 7
services.AddEntityFramework()
.AddSqlServer()
.AddDbContext(options => {
options.UseSqlServer(Configuration["Data:DefaultConnection:ConnectionString"]);
});
//MVC 6
services.AddMvc(setup =>
{
setup.Filters.AddService(typeof(UnitOfWorkFilter));
});
//..
}
This still leaves a question (see UPDATE 2 on my question). What if I want my controller to respond to an http POST request with a 201 Accepted with a Location header that includes the Id of the entity created in DB? When the controller's action finalises execution the changes have not yet been committed to DB therefore the Id of the entity created is still 0 until the action filter saves changes and the DB generates a value.