properly call EF SaveChanges after each request with Autofac managing scope - entity-framework

I would like to put in a bit of infrastructure on my project to SaveChanges on my db context at the end of every request.
So I create a simple piece of Owin middleware
app.Use(async (ctx, req) => {
await req();
var db = DependencyResolver.Current.GetService<MyDbContext>();
await db.SaveChangesAsync();
});
This does not work and throws the error
Instances cannot be resolved and nested lifetimes cannot be created from this LifetimeScope as it has already been disposed.
If I resolve the db before completing the request
app.Use(async (ctx, req) => {
var db = DependencyResolver.Current.GetService<MyDbContext>();
await req();
await db.SaveChangesAsync();
});
It doesn't throw an error but it also doesn't work (as in changes aren't saved to the db and viewing db in the debugger shows the DbSet's Local property throwing an InvalidOperationException about it being disposed.
I've tried with and without async, registering the middleware before and after autofac configuration (app.UseAutofacMiddleware(container)) and resolving the LifetimeScope directly from the Owin environment. All give me the same results.
I've done something like this before with Structuremap, but can't seem to figure the correct way to get Autofac to play nice.

Steven is right about the fact that you should not be committing on the request disposal because you cannot be sure if you really want to commit there, unless you abstract your UoW from DbContext and keep a success attribute there, checking if on disposal and conditionally commit.
For your specific question, there are two things to clarify.
DbContext or UoW need to be registered with InstancePerRequest()
Instead of using Owin middleware, you should use OnRelease(context => context.SaveMyChangesIfEverythingIsOk()) native Autofac API
For example, this is how it would look like for RavenDb
builder.Register(x =>
{
var session = x.Resolve<IDocumentStore>().OpenAsyncSession();
session.Advanced.UseOptimisticConcurrency = true;
return session;
})
.As<IAsyncDocumentSession>()
.InstancePerRequest()
.OnRelease(x =>
{
x.SaveChangesAsync();
x.Dispose();
});

Related

Error EF Core PostgreSQL during an entity insert

I am getting an error during an entity insert. I am using the Entity Framework Core with the PostgreSQL.
Here is a piece of code which produces an error:
public async Task Add(AddVideoDto dto)
{
var videoModel = mapper.Map<Video>(dto);
await context.Videos.AddAsync(videoModel);
await context.SaveChangesAsync();
}
Here is the error log:
fail: Microsoft.EntityFrameworkCore.Database.Connection[20004] et/oklike/oklikebe (master)
An error occurred using the connection to database 'oklikedb' on server 'tcp://127.0.0.1:5432'.
fail: Microsoft.AspNetCore.Server.Kestrel[13]
Connection id "0HLVLRDVR67DK", Request id "0HLVLRDVR67DK:00000001": An unhandled exception was thrown by the application.
System.InvalidOperationException: Reset() called on connector with state Connecting
at Npgsql.NpgsqlConnector.Reset()
at Npgsql.ConnectorPool.Release(NpgsqlConnector connector)
at Npgsql.NpgsqlConnection.<Close>g__FinishClose|76_1(NpgsqlConnection connection,
NpgsqlConnector connector)
at Npgsql.NpgsqlConnection.Close(Boolean wasBroken, Boolean async)
at Npgsql.NpgsqlConnection.CloseAsync()
at Npgsql.NpgsqlConnection.DisposeAsync()
at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.DisposeAsync()
at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.<>c__DisplayClass15_0.<<DisposeAsync>g__Await|0>d.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.<>c__DisplayClass15_0.<<DisposeAsync>g__Await|0>d.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at Microsoft.AspNetCore.Http.Features.RequestServicesFeature.<DisposeAsync>g__Awaited|9_0(RequestServicesFeature servicesFeature, ValueTask vt)
at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.FireOnCompletedAwaited(Task currentTask, Stack`1 onCompleted)
I am sure that I set up a connection to my db correctly. I verified that in the following way: I have another piece of code:
public async Task<List<GetVideoDto>> GetAll()
{
var videoModels = await context
.Videos
.ToListAsync();
return mapper.Map<List<GetVideoDto>>(videoModels);
}
And this piece of code works just fine. I manually inserted a value in my database and checked that it is returned by the await context.Videos.ToListAsync(); by debugging and by Postman. Also I can apply migrations to a database successfully.
So, the error seems to tell me that my piece of code tries to open a connection before closing it. But I can not understand how this could be possible.
I am very well aware of the state machine behind the async/await, so the context.SaveChangesAsync(); in my case will definitely run only after the context.Videos.AddAsync(videoModel); has completed.
UPDATE
I was able to better pin down the issue. The error is thrown due to this line:
await context.SaveChangesAsync();
So, I am not getting an error if I use the SaveChanges instead of the SaveChangesAsync. Does that mean that if I want to preserve the performance benefit of the SaveChangesAsync I should make the context to be not a singleton (as it is by default), but scoped?
Here is how I am adding the context right now:
services.AddDbContext<DataContext>(opt => opt.UseNpgsql(Configuration.GetConnectionString("DefaultConnection")));
I mean here is my entire Startup.ConfigureServices:
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<DataContext>(opt =>
opt.UseNpgsql(Configuration.GetConnectionString("DefaultConnection"))
);
services.AddCors();
services.AddControllers();
services.AddAutoMapper(typeof(Startup));
services.AddScoped<IVideoService, VideoService>();
}
And by the performance benefit of the SaveChangesAsync I mean that my thread won`t be idle waiting for the SaveChanges to complete, but will go back to the CLR thread pool.
I am strongly feeling that there should be a DDD principle which targets specifically the case of a correct SaveChangesAsync usage. But I can not find it (probably there is no one).
Add entities using plain old Add() rather than trying to add them async. Its not a long running operation just adding to an in memory collection so there is no benefit to trying to make the Add operation async.
When you are adding to your DbSet you are doing just that, it's the actual saving that benefits from being Async, as that's what you can await.
If you read the docs on AddAsync you will also see you should the following:-
This method is async only to allow special value generators, such as
the one used by
'Microsoft.EntityFrameworkCore.Metadata.SqlServerValueGenerationStrategy.SequenceHiLo',
to access the database asynchronously. For all other cases the non
async method should be used
.
I typically do this, and await the call to save in my controllers or whatever.
public void AddThing(Thing thingToAdd)
{
_context.Things.Add(thingToAdd);
}
public async Task<bool> SaveChangesAsync()
{
return (await _context.SaveChangesAsync() > 0);
}

Why (usually) there's a repository layer on BLoC pattern?

I'm new to Flutter and have just heard the BLoC concept from reading tutorials about Flutter. From this tutorial, I heard BLoC for the first time. But I also see a file called "Repository" in this article. Basically the data flow goes like this:
Web API --> Api Provider --> Repository --> BLoC --> Widget
What I don't understand is that why there's a need for the Repository layer, as when I look at the repository file, it's basically just returning the API Provider's Future result? I got curious and try to search further, and I see some of the people's coding patterns on the internet also has a Repository layer on it.
In the original article, the API Provider does everything. It calls the get request, it awaits for the Future resolve, it converts the JSON data into appropriate model, and return the model enclosed with Future.
class ApiProvider {
Future<ItemModel> fetchMovieList() async {
final response = await client.get("http://api.themoviedb.org/3/movie/popular?api_key=$_apiKey");
if (response.statusCode == 200)
return ItemModel.fromJson(json.decode(response.body));
else
throw Exception('Failed to load post');
}
}
class Repository {
ApiProvider _api = ApiProvider();
Future<ItemModel> fetchMovieList() => _api.fetchMovieList(); // why?
}
class Bloc {
Repository _repository = Repository();
final _moviesFetcher = PublishSubject<ItemModel>();
Observable<ItemModel> get allMovies => _moviesFetcher.stream;
fetchAllMovies() async {
ItemModel itemModel = await
_repository.fetchAllMovies();
_moviesFetcher.sink.add(itemModel);
}
}
Currently I modify it so that the Api Provider returns pure Future, where the Repository implement the .then() and convert the response into appropriate data, but I tend to avoid await because in React Native await causes the app to look unresponsive. I also move error checking into BLoC.
class ApiProvider {
Future fetchMovieList() => client.get("http://api.themoviedb.org/3/movie/popular?api_key=$_apiKey");
}
class Repository {
ApiProvider _api = ApiProvider();
Future<ItemModel> fetchMovieList() => _api.fetchMovieList().then(response => ItemModel.fromJson(json.decode(response.body));
}
class Bloc {
Repository _repository = Repository();
final _moviesFetcher = PublishSubject<ItemModel>();
Observable<ItemModel> get allMovies => _moviesFetcher.stream;
fetchAllMovies() async => _repository.fetchPopularMovies().then((response) => _moviesFetcher.sink.add(response))
.catchError((onError) => throw Exception("Failed to load post $onError"));
}
But still, I feel like this is a stretch to justify the need for this Repository layer. If I can, I want to make it like this:
class ApiProvider {
Future<ItemModel> fetchMovieList() => client.get("http://api.themoviedb.org/3/movie/popular?api_key=$_apiKey")
.then(response => ItemModel.fromJson(json.decode(response.body));
}
class Bloc {
ApiProvider _api = ApiProvider();
final _moviesFetcher = PublishSubject<ItemModel>();
Observable<ItemModel> get allMovies => _moviesFetcher.stream;
fetchAllMovies() async => _api.fetchPopularMovies().then((response) => _moviesFetcher.sink.add(response))
.catchError((onError) => throw Exception("Failed to load post $onError"));
}
and get rid of the Repository layer altogether. I'm not trying to say the Repository layer is unnecessary, but right now I don't know what pattern problem the Repository layer trying to solve. I just want to know why there's a Repository layer in the first place and what the real-world significant use case of Repository. I know this question may be flagged as a question that can trigger discussion instead of straight answers. But I believe there is some kind of narrowed answers for this question. I just can't find it when I tried to search on the internet (the search result got mixed up with other uses of "Repository" terms, like git and subversion).
Ok, forget about it. I found this excellent article that explains that basically Repository is to abstract where the data is coming from, whether it's from disk cache, cloud, or other source. The factory will decide what source to use based on the each source availability. The caller will just only need to go through one gate. Because the tutorial above has only one source (API/cloud), it looks useless to me at that moment.
Here is an excellent summary of the why. And it makes complete sense. This is from the BLoC documentation, where they detail a weather app tutorial that uses a Repository layer (see here for the full article).
"The goal of our repository layer is to abstract our data layer and
facilitate communication with the bloc layer. In doing this, the rest
of our code base depends only on functions exposed by our repository
layer instead of specific data provider implementations. This allows
us to change data providers without disrupting any of the
application-level code. For example, if we decide to migrate away from
metaweather, we should be able to create a new API client and swap it
out without having to make changes to the public API of the repository
or application layers."
I'm going for it!

Explicit transaction for entire request duration with automatic commit/rollback on errors (EF6, Web API2, NInject)

I'm starting a new Web API application, and I'm unsure how to handle transactions (and subsequent rollbacks in case of exceptions).
My overall goal is so have a single database connection per request, and have the entire thing wrapped in an explicit transaction.
I'll need an explicit transaction since I will be executing stored procedures aswell, and need to rollback any results from those if my application should throw any exceptions.
My plan was to re-use an approach I've used in MVC applications in the past which in rough terms was simply binding my database context to requestscope using ninject and then handling rollback/commit in the ondeactivation event.
Let's say I have a controller with two methods.
public class MyController : ApiController {
public MyController(IRepo repo) {
}
}
public string SimpleAddElement() {
_repo.Add(new MyModel());
}
public string ThisCouldBlowUp() {
// read from context
var foo = _repo.ReadFromDB();
// execute stored prodecure which changes some content
var res = _repo.StoredProcOperation();
// throw an exception due to bug/failsafe condition
if (res == 42)
throw Exception("Argh, an error occured");
}
}
My repo skeleton
public class Repo : IRepo {
public Repo(IMyDbContext context) {
}
}
From here, my plan was to simply bind the repositories using
kernel.Bind<IRepo>().To<Repo>();
and provide a single database context per request using
kernel.bind<IMyDbContext>().To<CreateCtx>()
.InRequestScope()
.OnDeactivate(FinalizeTransaction);
private IMyDbContext CreateCtx(IMyDbContext ctx) {
var ctx = new DbContext();
ctx.Database.BeginTransaction();
}
private void FinalizeTransaction(IMyDbContext ctx) {
if (true /* no errors logged on current HttpRequest.AllErrors */)
ctx.Commit();
else
ctx.Rollback();
}
Now, if I invoke SimpleAddElement from my browser FinalizeTransaction never gets invoked... So either I'm doing something wrong suddently, or missing something related to WebAPI pipeline
So how should I go about implementing a transactional "single DB session per request"-module?
What is best practise ?
If possible, I'd like the solution to support ASP vNext aswell
I suppose one potential solution could dropping the "ondeactivation" handler and implementing an HTTP module which will commit in Endrequest and rollback in Error... but there's just something about that I dont like.
You are missing an abstraction in your code. You execute business logic inside your controller, which is the wrong place. If you extract this logic to the business layer and hide it behind an abstraction, it will be trivial to wrap all business layer operations inside a transaction. Take a look at this article for some examples of this.

EF7 alpha connection state problems

I'm trying to use EF in a asp.net vNext SPA application.
I'm registering the context class with the build in dependency injection container using AddScoped() (just like they have it in the examples) but when I try to perform a delete operation on an entity I get weird errors.
Sometimes the delete works, sometimes I get a
Invalid operation. The connection is closed.
and sometimes I get a
The connection was not closed. The connection's current state is open.
This only happens for delete operations and I can't find a pattern on when the 'connection is open' and 'connection is closed' appear.
Here's my delete method body (the method is virtual because this is a base controller, though no overrides exist for it yet):
public virtual async Task<IActionResult> Delete(int id)
{
var t = await Items.SingleOrDefaultAsync(i => i.ID == id);
if (t == null)
return new HttpStatusCodeResult((int)HttpStatusCode.NoContent);
Items.Remove(t);
AppContext.SaveChanges();
return new HttpStatusCodeResult((int)HttpStatusCode.OK);
}
Problem disappeared after migrating to alpha3

EF + UnitOfWork + SharePoint RunWithElevatedPrivileges

In our SharePoint application we have used the UnitOfWork + Repository patterns together with Entity Framework. To avoid the usage of the passthrough authentication we have developed a piece of code that impersonate a single user before creating the ObjectContext instance in a similar way that is described in "Impersonating user with Entity Framework" on this site.
The only difference between our code and the referred question is that, to do the impersonation, we are using RunWithElevatedPrivileges to impersonate the Application Pool identity as in the following sample.
SPSecurity.RunWithElevatedPrivileges(delegate() {
using (SPSite site = new SPSite(url)) {
_context = new MyDataContext(ConfigSingleton.GetInstance().ConnectionString);
}
});
We have done this way because we expected that creating the ObjectContext after impersonation and, due to the fact that Repositories are receiving the impersonated ObjectContext would solve our requirement.
Unfortunately it's not so easy. In fact we experienced that, even if the ObjectContext is created before and under impersonation circumstances, the real connection is made just before executing the query, and so does not use impersonation, which break our requirement.
I have checked the ObjectContext class to see if there was any event through which we can inject the impersonation but unfortunately found nothing.
Any help?
We had a simillar problem when we used LinqToSharePoint. The DataContext is created from the HttpContext.Current and did not consider the RunWithElevatedPrivileges method. We did a nasty workaround that we backed up the original HttpContext, created a new dummy HttpContext in the RunWithElevatedPrivileges method and the problem went away. Obviously we set the context to the original afterwards.
Edit:
You can use the method below to create new dummy HttpContext.Call this method as first in your RunWithElevatedPrivileges. In the normal context just backup your currenct context with var backupContext = HttpContext.Current and after everything is done just set the context back.
private void SetNewContextWeb(SPWeb oWeb)
{
HttpRequest httpRequest = new HttpRequest(string.Empty, oWeb.Url, string.Empty);
HttpContext.Current = new HttpContext(httpRequest, new HttpResponse(new System.IO.StringWriter()));
SPControl.SetContextWeb(HttpContext.Current, oWeb);
}