How to properly implement DbCommandInterceptor with per-DbContext state? - c#

I am following Tom Dykstra's Getting Started with Entity Framework 6 Code First using MVC 5 tutorial. Part 4 of this tutorial covers EF6's connection resiliency and command interception features.
As a way of demonstrating the use of command interception, the tutorial provides two example DbCommandInterceptor implementations. One (SchoolInterceptorLogging) interfaces with a logger to record each SQL command that is executed, how much time it took to execute, and whether there was an exception. The other example (SchoolInterceptorTransientErrors) simulates transient DB errors so that connection resiliency can be tested.
Although the tutorial does not specifically mention the issue of synchronization, I assume that because a single instance of the DbCommandInterceptor is registered via DbInterception.Add(), that any per-DbContext state utilized by the DbCommandInterceptor must be synchronized. For example, SchoolInterceptorLogging should probably synchronize use of the _stopwatch, and SchoolInterceptorTransientErrors should probably synchronize the _counter.
I thought about using thread-local storage via ThreadStaticAttribute or ThreadLocal<T>. However, I am not sure that this is sufficient. Suppose that my application uses DbContext.SaveChangesAsync() to asynchronously save all changes. Isn't it possible for the same thread to handle two asynchronous save operations? If so, then thread-local storage wouldn't work.
Another idea is to store per-DbContext state in the call context. However, when using the CallContext, it is recommended that only immutable types should be used. (See Stephen Cleary's blog post, Implicit Async Context ("AsyncLocal").)
A third idea is to use a ConcurrentDictionary where the keys are the DbCommandInterceptionContext object passed to NonQueryExecuting()/NonQueryExecuted(), ReaderExecuting()/ReaderExecuted(), or ScalarExecuting()/ScalarExecuted(), and the values are a state object. However, I have two questions about this approach:
Is the DbCommandInterceptionContext object that is passed to the *Executing()/*Executed() method distinct for each save operation?
From setting a breakpoint in ReaderExecuting() and calling GetHashCode() on the interception context object, it appears to be distinct for each retry let alone save operation (tested EntityFramework version 6.1.3).
Will the *Executed() method always be called?
This is to make sure that anything added to the ConcurrentDictionary in the *Executing() method can always be cleaned up by the *Executed() method.
So, how should a DbCommandInterceptor with per-DbContext state be implemented?

Related

Best way of dealing with shared state in a real time system in dotnet core background service

I have a background service IHostedService in dotnet core 3.1 that takes requests from 100s of clients(machines in a factory) using sockets (home rolled). My issue is that multiple calls can come in on different threads to the same method on a class which has access to an object (shared state). This is common in the codebase. The requests also have to be processed in the correct order.
The reason that this is not in a database is due to performance reasons (real time system). I know I can use a lock, but I don't want to have locks all over the code base.
What is a standard way to handle this situation. Do you use an in-memory database? In-memory cache? Or do I just have to add locks everywhere?
public class Machine
{
public MachineState {get; set;}
// Gets called by multiple threads from multiple clients
public bool CheckMachineStatus()
{
return MachineState.IsRunning;
}
// Gets called by multiple threads from multiple clients
public void SetMachineStatus()
{
MachineState = Stopped;
}
}
Update
Here's an example. I have a console app that talks to a machine via sockets, for weighing products. When the console app initializes it will load data into memory (information about the products being weighed). All of this is done on the main thread, to keep data integrity.
When a call comes in from the weigh-er on Thread 1, it will get switched to the main thread to access the product information, and to finish any other work like raising events for other parts of the system.
Currently this switching from Thread 1,2, ...N to the main thread is done by a home rolled solution, and was done to avoid having locking code all over the code base. This was written in .Net 1.1 and since moving to dotnet core 3.1. I thought there might be a framework, library, tool, technique etc that might handle this for us, or just a better way.
This is an existing system that I'm still learning. Hope this makes sense.
Using an in-memory database is an option, as long as you are willing to delegate all concurrency-inducing situations to the database, and do nothing using code. For example if you must update a value in the database depending on some condition, then the condition should be checked by the database, not by your own code.
Adding locks everywhere is also an option, that will almost certainly lead to unmaintanable code quite quickly. The code will probably be riddled with hidden bugs from the get-go, bugs that you will discover one by one over time, usually under the most unfortunate of circumstances.
You must realize that you are dealing with a difficult problem, with no magic solutions available. Managing shared state in a multithreaded application has always been a source of pain.
My suggestion is to encapsulate all this complexity inside thread-safe classes, that the rest of your application can safely invoke. How you make these classes thread-safe depends on the situation.
Using locks is the most flexible option, but not always the most efficient because it has the potential of creating contention.
Using thread-safe collections, like the ConcurrentDictionary for example, is less flexible because the thread-safety guarantees they offer are limited to the integrity of their internal state. If for example you must update one collection based on a condition obtained from another collection, then the whole operation can not be made atomic by just using thread-safety collections. On the other hand these collections offer better performance than the simple locks.
Using immutable collections, like the ImmutableQueue for example, is another interesting option. They are less efficient both memory and CPU wise than the concurrent collections (adding/removing is in many cases O(Log n) instead of O(1)), and not more flexible than them, but they are very efficient specifically at providing snapshots of actively processed data. For updating atomically an immutable collection, there is the handy ImmutableInterlocked.Update method available. It updates a reference of an immutable collection with an updated version of the same collection, without using locks. In case of contention with other threads it may invoke the supplied transformation multiple times, until it wins the race.

Any difference between using the default DbContext vs SpecificDbContext as service dependency?

We use multiple micro-service applications, each with it's own specific DbContext. Few entities are duplicated in all of those contexts by necessity, for example - the Region entity. I want to use a single service to perform CRUD on Regions in all db contexts. That's why I've used the default DbContext as dependency in this service, relying on the IoC container in each micro-service app to provide it's own specific, let's call it ExampleDbContext. Then I use Set<Region> to manipulate the entity.
I get an inconsistent behavior - sometimes it works, while most of the time I get:
InvalidOperationException: An attempt was made to use the context while it is being configured. A
DbContext instance cannot be used inside OnConfiguring since it is
still being configured at this point. This can happen if a second
operation is started on this context before a previous operation
completed...
From what I can gather the default culprit is simultaneous usage of the same DbContext instance. All our methods are async so it is certainly possible, but I find it unlikely, since the code that throws is called once on the application start inside the Program.Main method. Either way, I am not sure how to confirm it or rule that out.
What I find strange about this is that if I replace DbContext with an explicit ExampleDbContext this error is no longer thrown. Thus I am lead to believe that there is some difference in how the default DbContext is instantiated.
As a further note I think that ExampleDbContext is instantiated 3 times, because a breakpoint inside it's OnConfiguring method gets hit 3 times.
Edit
Turns out using the specific ExampleDbContext also throws, however much more rarely.
Edit 2
Alright, after another day debugging and commenting out code to pin-point the issue, I can confirm that it was indeed parallel calls to the same DbContextinstance.
One piece is still still missing from the puzzle:
- Why using DbContext instead of ExampleDbContext threw more frequently?
Overall I guess the moral of the story is "Take your time to eliminate the obvious cause of the issue". When that's off the tables think about other causes and only then post about asking help.

Are there any technical reasons Simple Injector cannot support Web API on .NET 4.0?

This is really a follow up on this question. One of the Simple Injector developers pointed out a useful tidbit about Simple Injector, and I thought it would be good to make it more accessible.
So, are there any technical hurdles to supporting Simple Injector with Web API 1 and .NET 4.0? The source code is easy enough to download and compile back. It seems to work just fine.
We deliberately chose to NOT support .NET 4.0 for Web API, because the WebApiRequestLifestyle makes use of CallContext.LogicalGetData which behaves different under .NET 4.0. This behavior is so significantly different that it can cause bugs when using nested ExecutionContextScope instances in background threads and Tasks that run in parallel.
What changed in this respect is that in .NET 4.5 the Logical Call Context exhibits copy-on-write behavior, which means that when the Logical Call Context is changed from within a parallel operation, it has no impact on the original operation that has spawn this parallel operation. In .NET 4.0, any change to the Logical Call Context from within a parallel operation will be observable from within the main operation.
We decided to depend on this copy-on-write behavior of .NET 4.5, since it allows to have multiple parallel operations been spawned from the main operation which could all start their own ExecutionContextScope (which is what the Web API integration package uses in the background) to run in isolation. This allows them to have their own child scope and when the scope is disposed they run again in the scope of the main operation. Starting in a new scope in a background thread is typically what you would like to do, since your components would otherwise be accessed in parallel, while they might not be thread-safe at all. Starting a new scope ensures that when a new object graph is resolved from the container, new instances are created if they are registered as Per Web API Request or as Per Execution Scope.
Without this copy-of-write behavior, parallel operations would interfere with each other and would see the scopes of other parallel operations, which causes those scopes to get nested, while they in practice will not nest, but overlap. This will cause all sorts of problems such as resulting in falling back to the scope of another parallel operation (instead of falling back on the main operation's scope). This is of course incorrect behavior.
As long as you only start new ExecutionContextScope's in the asynchronous flow (or don't start new scopes at all) instead of starting new scopes in parallel operations, the problem does not exist and your code would run the same under .NET 4.0 and .NET 4.5.
But since this behavior is so fundamentally different and could cause all kinds of problems, or when it seems to work, might again break when you switch to .NET 4.5, we decided that it would be wise to don't try to support .NET 4.0 at all. This prevents developers from falling into this trap, and it makes our own work much easier, since we don't have to document this fundamental difference and it saves us a lot of support time as well, since no matter how good the documentation is, developers will try to use it under .NET 4.0 anyway and this will possibly trigger many new questions on both Stackoverflow and the Simple Injector forum, which we will have to answer.
This didn't seem quite like a comment, but it's not quite an answer either -- more of a side car.
I wanted to add to #Steven's great explanation. CallContext.LogicalGetData() is one of those little gems inside the .NET Framework. Unfortunately, it's behavior has changed over time, and there are definitely, ahem, subtleties. There's also a dearth of information on the topic. So here are some resources:
Mr. CLR himself -- Jeffrey Richter on the topic : http://www.wintellect.com/blogs/jeffreyr/logical-call-context-flowing-data-across-threads-appdomains-and-processes
SO's own Stephen Cleary - http://blog.stephencleary.com/2013/04/implicit-async-context-asynclocal.html
Another S. Cleary post explaining the behavior in relation to asp.net - Using ASP.NET Web API, my ExecutionContext isn't flowing in async actions
CallContext.LogicalGetData Vs. CallContext.GetData

Should the DbContext in EF have a short life span?

I have a few long running tasks on my server. Basically they are like scheduled tasks - they run from time to time.
They all required access to the DB and I use Entity Framework for that. Each task uses a DbContext for access.
Should the DbContext object be recreated on every run or should I reuse it?
I should say "it depends" as there are probably scenarios where both answers are valid, however the most reasonable answer is "the context should be disposed as soon as it is not needed" which in practice means "dispose rather sooner than later".
The risk that comes from such answer is that newcomers sometimes conclude that the context should be disposed as otfen as possible which sometimes lead to a code I review where there are consecutive "usings" that create a context, use it for one or two operations, dispose and then another context comes up next line. This is of course not recommended also.
In case of web apps, the natural lifecycle is connected with a lifecycle of web requests. In case of system services / other long running applications one of lifecycle strategies is "per business process instance" / "per usecase instance" where business processing / use case implementations define natural borders where separate instances of contexts make sense.
Yes, DbContext should only live for a very short time. It is effectively your unit of work
You should definitely create it each time you're going to use it. (Well, you should inject it but that's another discussion :-))
Update : OK, I accept that 'create it each time you're going to use it' could be misleading. I'm so used to context being an instance on a class that is injected and so lives only for the life of a request that I struggle to think of it any other way... #wiktor's answer is definitely better as it more correctly expresses the idea that you should "dispose sooner rather than later"

How do I 'span' a transaction over two unrelated, or decoupled, method calls?

I'm busy building a software update application in C#, WinForms, .NET 3.5, where I have a collection of pluggable task classes with a common base class. I would like one task, the database upgrade, to begin a transaction, and another task, the web site upgrade, to commit or roll back the same transaction, so the web site and DB are always in sync.
I vaguely remember stuff from my VB6 days where a COM+ method could enlist in a transaction if one was already running, or begin one if not, etc. I also have vague memories of this porting to .NET Enterprise Services, but that was also a while ago.
What is the current technology to use to achieve this?
I think you are looking for environment transactions, or implicit transactions
using (TransactionScope scope = new TransactionScope())
{
// do several stuff in the same transaction
// calls in here implicitly are in the scope of the transaction.
// you open several independent connections, which are in the same transaction.
}
You might want to start here.
http://msdn.microsoft.com/en-us/library/86773566.aspx
SqlConnection.BeginTransaction returns a SqlTransaction, which implements IDbTransaction.
The two methods defined on IDbTransaction are Commit() and Rollback(). If you keep the connection object alive between calls, you should be able to pass the transaction from one place to another and perform the commit or rollback there.
If you're not using SQL Server, your database provider (OleDb, Odbc, etc.) will provide a corresponding object.
Off the top of my head, I think you should be able to do this w/o special technology. Create an UpgradeManager class that is responsible for kicking off both the database and web upgrades. The transaction should live here and be called surrounding the calls into the two other objects.
If you have other tasks to plug in, have the UpgradeManager iterate over a collection of your Tasks.
.....or you could pass the transaction around, like harpo said (his response came in the middle of composing mine)... good to have options. ;-)
Nate

Categories

Resources