tl;dr How can I use Entity Framework in a multithreaded .NET Core API application even though DbContext is not threadsafe?
Context
I am working on a .NET Core API app exposing several RESTful interfaces that access the database and read data from it, while at the same time running several TimedHostedServices as background working threads that poll data regularly from other webservices and store them into the database.
I am aware of the fact that DbContext is not threadsafe. I read a lot of docs, blog Posts and answers here on Stackoverflow, and I could find a lot of (partly contradictory) answers for this but no real "best practice" when also working with DI.
Things I tried
Using the default ServiceLifetime.Scoped via the AddDbContext extension method results in exceptions due to race conditions.
I don't want to work with locks (e.g. Semaphore), as the obvious downsides are:
the code is polluted with locks and try/catch/finally for safely releasing the locks
it doesn't really seem 'robust', i.e. when I forget to lock a region that accesses the DbContext.
it seems redundant and 'unnatural' to artificially syncronize db access in the app when working with a database that also handles concurrent connections and access
Not injecting MyDbContext but DbContextOptions<MyDbContext> instead, building the context only when I need to access the db, using a using statement to immediatelly dispose it after the read/write seems like a lot of resource usage overhead and unnecessarily many connection opening/closings.
Question
I am really puzzled: how can this be achived?
I don't think my usecase is super special - populating the db from a Background worker and querying it from the web API layer - so there should be a meaningful way of doing this with ef core.
Thanks a lot!
You should create a scope whenever your TimedHostedServices triggers.
Inject the service provider in your constructor:
public MyServiceService(IServiceProvider services)
{
_services = services;
}
and then create a scope whenever the task triggers
using (var scope = _services.CreateScope())
{
var anotherService = scope.ServiceProvider.GetRequiredService<AnotherService>();
anotherService.Something();
}
A more complete example is available in the doc
Another approach to create own DbContextFactory and instantiate new instance for every query.
public class DbContextFactory
{
public YourDbContext Create()
{
var options = new DbContextOptionsBuilder<YourDbContext>()
.UseSqlServer(_connectionString)
.Options;
return new YourDbContext(options);
}
}
Usage
public class Service
{
private readonly DbContextFactory _dbContextFactory;
public Service(DbContextFactory dbContextFactory)
=> _dbContextFactory = dbContextFactory;
public void Execute()
{
using (var context = _dbContextFactory.Create())
{
// use context
}
}
}
With factory you don't need to worry about scopes anymore, and make your code free of ASP.NET Core dependencies.
You will be able to execute queries asynchronously, which not possible with scoped DbContext without workarounds.
You always be confident about what data saved when calling .SaveChanges(), where with scoped DbContext there are possibilities that some entity were changed in other class.
Related
I recently came across AddPooledDbContextFactory concept as part of my NET 5 self-education piece and am keen to implement it properly. However, I am not sure how to use it with generics that I generally use.
Example of my current setup:
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<TestDbContext>(
(s, o) => o.UseNpgsql(Configuration.GetConnectionString("DatabaseConnection"))
.UseLoggerFactory(s.GetRequiredService<ILoggerFactory>()));
// other code //
}
my repository generic:
public class Repository<T> : IRepository<T> where T
{
private readonly TestDbContext _dbContext;
public Repository(TestDbContext dbContext)
{
_dbContext = dbContext;
}
public async Task Create(T entity)
{
await _dbContext.Set<T>().AddAsync(entity);
await _dbContext.SaveChangesAsync();
}
// other methods //
}
this is invoked in following manner as example:
public class WeatherForecastController : ControllerBase
{
private readonly IRepository<Test> testRepo;
public WeatherForecastController(IRepository<Test> testRepo)
{
this.testRepo= testRepo;
}
[HttpGet]
public async Task<IEnumerable<WeatherForecast>> GetAsync()
{
await testRepo.Create(new Test { Name = "Superman" });
// other code
}
}
I would like to convert this to use the new AddPooledDbContextFactory concept but cannot find enough documentation to figure out how to do this.
Atm only thing that comes to mind is using statements at each method but that doesn't make sense.
Any advice on this?
Documentation is not yet complete and is in progress, you track this issue
https://github.com/dotnet/EntityFramework.Docs/issues/2523
You can also a look at the tests for AddPooledDbContextFactory to see how to register DbContext with
https://github.com/dotnet/efcore/search?q=AddPooledDbContextFactory
for example to register DbContext:
services.AddPooledDbContextFactory<TContext>(ob =>
ob.UseSqlServer("ConnectionString").EnableServiceProviderCaching(false), poolSize: 32)
Then in your class, inject an IDbContextFactory<TContext> and use it like this:
using(var context = _factory.CreateDbContext())
{
var orders = await context.Orders.Where(o => o.Id > 3).ToListAsync();
}
According to this post:
Note that the DbContext instances created in this way are not managed
by the application's service provider and therefore must be disposed
by the application
You can also check out this post to see how to use IDbContextFactory:
https://learn.microsoft.com/en-us/aspnet/core/blazor/blazor-server-ef-core?view=aspnetcore-5.0
#Aeseir your code looks good to me. You are following best practices and you don't need to change it.
You are using the Repository Pattern, so your Repository class has all of your query logic which helps create loosely coupled and maintainable code.
In your ConfigureServices, calling: services.AddDbContext<TestDbContext>() registers TestDbContext with Scoped service lifetime. This is the way that DbContext is designed to work, and it will also work well with ASP.NET controllers, since they have a Scoped lifetime as well.
You did not show your code for registering IRepository, but that service lifetime should be Scoped as well. Btw, you can tell BuildServiceProvider() to validate scope registrations:
builder.Services.BuildServiceProvider(validateScopes: true);
Since DbContext is designed to have a Scoped service lifetime, and since your IRepository and Controller services are Scoped as well, every request gets brand new:
Controller
IRepository
DbContext
Those services are used for the request and then Diposed. This is how ASP.NET is intended to work.
Apparently at some point, DbContext pooling has been introduced to improve performance. In this case, EF Core manages a pool of context instances for you and resets them after each request. This can improve performance, although in some situations, the benefit might be small. See MSDN documentation for more details.
I think for use with ASP.NET controllers (i.e. the code you posted above) all you need to do to take advantage of EF Core context pooling is call AddDbContextPool():
builder.Services.AddDbContextPool<ApplicationDbContext>(/* ... */);
However, if you needed to use DbContext in services registered with Singleton lifetime, then the pattern above would not work well. Because when a Scoped service gets used in a Singleton service, the Scoped service is essentially a Singleton. Each request would not get a new DbContext, nor a reset one from the pool. (See QUESTION below.)
In that case, you might want to use the DbContext factory pattern instead:
builder.Services.AddDbContextFactory<ApplicationDbContext>(/* ... */);
Or, if you want to use context pooling with a factory pattern:
builder.Services.AddPooledDbContextFactory<ApplicationDbContext>(/* ... */);
The DbContextFactory can then be used in other services through constructor injection. For example:
private readonly IDbContextFactory<ApplicationDbContext> _contextFactory;
public MyController(IDbContextFactory<ApplicationDbContext> contextFactory)
{
_contextFactory = contextFactory;
}
The injected factory can then be used to construct DbContext instances in the controller code. For example:
public void DoSomething()
{
using (var context = _contextFactory.CreateDbContext())
{
// ...
}
}
Keep in mind that when you call CreateDbContext(), context instances are not managed by the service provider and therefore must be disposed by the application. Hence you need to Dispose of them yourself, such as in the example above which does so with the using statement.
QUESTION
I am doing my best to understand this stuff and explain it, but I might be wrong, so please call out an inaccuracies in my post.
When using AddDbContextPool(), does the DbContext get registered as a Singleton or Scoped?
I found in MSDN documentation that it's effectively registered as a Singleton:
Context pooling works by reusing the same context instance across requests; this means that it's effectively registered as a Singleton, and the same instance is reused across multiple requests (or DI scopes). This means that special care must be taken when the context involves any state that may change between requests.
However, I have found that if AddDbContextPool() is used along with true for validatedScopes:
builder.Services.BuildServiceProvider(validateScopes: true)
When DbContext is consumed from another service which is registered as a Singleton, the following exception is thrown:
System.InvalidOperationException: 'Cannot consume scoped service 'ApplicationDbContext' from singleton 'IRepository'.'
Hence why I stated above that DbContext still gets Scoped service lifetime.
About 2 years ago, we made the change from ADO.net over to Entity Framework 6. Initially, we simply instantiated our DbContexts where we needed them. However, at some point we started down the path of prepping for implementing Dependency Injection in the solution. As such, our DbContexts were injected into our MVC controller constructors, and then the necessary logic classes were instantiated directly using the DbContexts. For awhile, this worked great as we had certain IRepository implementations that allowed us to manipulate dozens of entities across multiple repositories, and save them all with a single SaveChanges call.
However, over time, we've started to adapt a more purist DI approach where all our new classes are being injected (rather than instantiated). As a side-effect, we've started moving away from repositories and towards using EF as just a core repository across our solution. This has lead to us building modules in our application that perform their unit of work and save their changes. So rather than having dozens of repositories being used and accessed to perform an operation, we simply use the DbContext.
Initially, this worked out alright as we were injecting our DbContexts as scoped, and the functionality was unchanged. However, with the move towards more self-contained, self-saving modules, we've encountered concurrency errors with our new functionality. We managed to solve the concurrency issues by switching the DI configuration for our DbContexts over to transient. This presented each self-contained module with a new DbContext and they were able to execute and save without caring what the other modules were doing.
However, switching the DbContexts over to transient had the unfortunate side-effect of making it impossible to switch our legacy modules over to our DI container as they relied on a singular shared DbContext across all of their injected dependencies.
So my main conundrum is whether we should make our DbContexts Scoped or Transient. And if we do settle on scoped, how do we write our new modules so that they can execute in a parallel way? And if we settle on transient, how can we preserve the functionality in our dozens of legacy classes that are still developed and used?
Scoped
Pros
Single DbContext per request. No worries about entities being tracked in different contexts, and saves can be done wholesale.
Legacy Code does not need any major changes to be switched to DI.
Cons
Unrelated tasks can't execute concurrently using the same context.
Developers must constantly be aware of the state of the current context. They need to be wary of any side-effects from other classes utilizing the same context.
System.NotSupportedException: 'A second operation started on this context before a previous asynchronous operation completed. Use 'await' to ensure that any asynchronous operations have completed before calling another method on this context. Any instance members are not guaranteed to be thread safe.' thrown during concurrent operations.
Transient
Pros
New DbContext per class. No worries about locking context while performing most operations on the context.
Modules become self-contained and you don't need to worry about side-effects from other classes.
Cons
Receiving an entity from one context and attempting to use it in a different context instance can cause errors.
No ability to perform batch operations across multiple different classes sharing the same context.
Here is a demo algorithm to force a concurrency error for a scoped context. It presents a possible use-case for the transient injection.
// Logic Class
public class DemoEmrSaver
{
private readonly DbContext_dbContext;
public DemoEmrSaver(DbContext dbContext)
{
_dbContext = dbContext;
}
public Task CreateEmrs(int number)
{
Contract.Assert(number > 0);
for (var i = 0; i < number; i++)
CreateEmr();
return _dbContext.SaveChangesAsync();
}
private void CreateEmr()
{
var emr = new EMR
{
Name = Guid.NewGuid().ToString()
};
_dbContext.EMRs.Add(emr);
}
}
// In a controller
public async Task<IActionResult> TestAsync()
{
// in reality, this would be two different services.
var emrSaver1 = new DemoEmrSaver(_dbContext);
var emrSaver2 = new DemoEmrSaver(_dbContext);
await Task.WhenAll(emrSaver1.CreateEmrs(5), emrSaver2.CreateEmrs(5));
return Json(true);
}
And here is a demo of how the older services often functioned
public class DemoEmrSaver
{
private readonly DbContext _dbContext;
public DemoEmrSaver(DbContext dbContext)
{
_dbContext = dbContext;
}
public void CreateEmrs(int number)
{
Contract.Assert(number > 0);
for (var i = 0; i < number; i++)
CreateEmr();
}
private void CreateEmr()
{
var emr = new EMR
{
Name = Guid.NewGuid().ToString()
};
_dbContext.EMRs.Add(emr);
}
}
// controller action
public async Task<IActionResult> TestAsync()
{
var emrSaver1 = new DemoEmrSaver(_dbContext);
var emrSaver2 = new DemoEmrSaver(_dbContext);
emrSaver1.CreateEmrs(5);
emrSaver2.CreateEmrs(5);
await _catcContext.SaveChangesAsync();
return Json(true);
}
Is there some sort of middle ground that won't require massive overhauls to the old code, but that still enables my new modules to be defined and utilized in a simple way (e.g. avoiding having to pass a Func of some sort into each constructor to get a new instance, and avoid having to specifically a request a fresh DbContext everywhere I need one?
Also probably important, I'm using the .Net Core DI Container from the Microsoft.Extensions.DependencyInjection namespace.
Why not to use an artificial scopes were you have this difficulties?
For example, we have some background services in our codebase, when they are used inside a normal AspNet core web app, as you say, the context are bounded to the requests, but for our console apps, we do not have the concept of scoped, so we have to define it ourselves.
To create an artificial scope, simply inject an IServiceScopeFactory, then, everything inside will utilize the new, separated context.
public class SchedulerService
{
private readonly IServiceScopeFactory _scopeService;
public SchedulerService(IServiceScopeFactory scopeService)
{
_scopeService = scopeService;
}
public void EnqueueOrder(Guid? recurrentId)
{
// Everything you ask here will be created as if was a new scope,
// like a request in aspnet core web apps
using (var scope = _scopeService.CreateScope())
{
var recurrencyService = scope.ServiceProvider.GetRequiredService<IRecurrencyService>();
// This service, and their injected services (like the context)
// will be created as if was the same scope
recurrencyService.ProcessScheduledOrder(recurrentId);
}
}
}
This way you can control the lifetime of the scoped services, helping you to share the same context inside that block.
I would recommend to create just one service this way, and then inside the service program everything as normal, this way your code will be keep clean and easier to read, so, do like the example:
using (var scope = _scopeService.CreateScope())
{
var recurrencyService = scope.ServiceProvider.GetRequiredService<IRecurrencyService>();
// In this service you can do everything and is
// contained in the same service
recurrencyService.ProcessScheduledOrder(recurrentId);
}
Please do not add complex code inside the using, something like
using (var scope = _scopeService.CreateScope())
{
var recurrencyService = scope.ServiceProvider.GetRequiredService<IRecurrencyService>();
var otherService= scope.ServiceProvider.GetRequiredService<OtherService>();
var moreServices = scope.ServiceProvider.GetRequiredService<MoreServices>();
var something = recurrencyService.SomeCall();
var pleaseDoNotMakeComplexLogicInsideTheUsing = otherService.OtherMethod(something);
...
}
EDIT
My fear with this approach is that it's applying a Service Locator
pattern, and I've often seen that dismissed as an anti-pattern where
DI is concerned
An anti-pattern would be to use this as normal work, but I am suggesting to introduce it in just one part, there are limits and constraints to what DI can do and can help you with your problems.
For example, property injection (no constructor injection) are also a code smell, but it is not banned or deleted of the framework, because in some cases is the only solution, or the most simple, and keeping things simple is more important than keep all the good practices (even best practices are not white or black, sometimes you will have to do trade-offs between follow one or other principle).
My solution should be in one part of your program, not for everything, that is why I recommend to create just one service, and from there make all the services, you can not use constructor injection to break the scoped life cycle, so IServiceScopeFactory exists just for that.
And sure, it is not for general use, but to help with lifecycle problems like you have.
If you are worried about calling GetService<SomeClass> you can create an abstraction to keep your code clean, for example, I created this general service:
public class ScopedExecutor
{
private readonly IServiceScopeFactory _serviceScopeFactory;
private readonly ILogger<ScopedExecutor> _logger;
public ScopedExecutor(
IServiceScopeFactory serviceScopeFactory,
ILogger<ScopedExecutor> logger)
{
_serviceScopeFactory = serviceScopeFactory;
_logger = logger;
}
public async Task<T> ScopedAction<T>(Func<IServiceProvider, Task<T>> action)
{
using (var scope = _serviceScopeFactory.CreateScope())
{
return await action(scope.ServiceProvider);
}
}
public async Task ScopedAction(Func<IServiceProvider, Task> action)
{
using (var scope = _serviceScopeFactory.CreateScope())
{
await action(scope.ServiceProvider);
}
}
}
Then i have this extra layer (you could make this in the same class as the previous)
public class ScopedExecutorService<TService>
{
private readonly ScopedExecutor _scopedExecutor;
public ScopedExecutorService(
ScopedExecutor scopedExecutor)
{
_scopedExecutor = scopedExecutor;
}
public Task<T> ScopedActionService<T>(Func<TService, Task<T>> action)
{
return _scopedExecutor.ScopedAction(serviceProvider =>
action(
serviceProvider
.GetRequiredService<TService>()
)
);
}
}
Now, where you need your services as a separated context, you can use it something like this
public class IvrRetrieveBillHistoryListFinancingGrpcImpl : IvrRetrieveBillHistoryListFinancingService.IvrRetrieveBillHistoryListFinancingServiceBase
{
private readonly GrpcExecutorService<IvrRetrieveBillHistoryListFinancingHttpClient> _grpcExecutorService;
public IvrRetrieveBillHistoryListFinancingGrpcImpl(GrpcExecutorService<IvrRetrieveBillHistoryListFinancingHttpClient> grpcExecutorService)
{
_grpcExecutorService = grpcExecutorService;
}
public override async Task<RetrieveBillHistoryListFinancingResponse> RetrieveBillHistoryListFinancing(RetrieveBillHistoryListFinancingRequest retrieveBillHistoryListFinancingRequest, ServerCallContext context)
{
return await _grpcExecutorService
.ScopedLoggingExceptionHttpActionService(async ivrRetrieveBillHistoryListFinancingHttpClient =>
await ivrRetrieveBillHistoryListFinancingHttpClient
.RetrieveBillHistoryListFinancing(retrieveBillHistoryListFinancingRequest)
);
}
}
As you see, no service.GetService is called in the business code, just in one place in our toolkit
I want to share a DB context with another method called from outside (inherited class) without creating a new context unless it is being disposed. I want to check the context is disposed so that I could create new context.
It's rest api. There is a bulk upload for multiple entities and I want to share the transaction so if one fail, it will not be committed to DB
Regardless of the comments questioning design quality, valid scenarios exist were the dbContext could be in a disposed state, such as (not a complete list):
For example (within injected dbContext MVC services):
your service iterates though a lower tier of one-or-more service calls, possibly using asynchronous socket handler on a lower tier API library, with each response using the parent requester dbContext.
Your service calls a database job, (asynchronous task or not).
Exception handling logging to database (if the dbContext is already lost - avoid loss of logging debug details)
Note: Long running processes using dbContext like this should follow good practice of avoiding dbContext bloat such as using AsNoTracking() method were possible - as bloat can quickly become a concern.
Performance consideration:
Most trusted option is to recreate the dbContext on each child (api call/async task), but this may incur undesired performance overheads, such as when dealing with 1000's of api iterative calls and atomic unit transactions are not viable.
Solution Tested Using Framework:
Entity Type: Microsoft.EntityFrameworkCore.DbContext
Version=5.0.16.0, Culture=neutral, PublicKeyToken=adb9793829ddae60
Warnings:
Lots of warning advice available on this type of extended dbContext use, such use should be used with caution/avoided where possible.
See warning details : c-sharp-working-with-entity-framework-in-a-multi-threaded-server
Extend you DbContext with partial class Or add method to your existing extended partial class.
FYI - Please comment if still working on updated EntityFrameworkCore libraries.
public partial class FooDbContext : DbContext
{
// Using Type: 5.0.16.0 EntityFrameworkCore.DbContext (confirm if working with any core library upgrades)
public bool IsDisposed()
{
bool result = true;
var typeDbContext = typeof(DbContext);
var isDisposedTypeField = typeDbContext.GetField("_disposed", BindingFlags.NonPublic | BindingFlags.Instance);
if (isDisposedTypeField != null)
{
result = (bool)isDisposedTypeField.GetValue(this);
}
return result;
}
}
Usage:
if (fooDbContext == null || fooDbContext.IsDisposed())
{
// Recreate context
}
I noticed the project template for MVC when using individual user accounts puts a few objects in the current Owin context (in App_Start/Startup.Auth.cs):
// Configure the db context, user manager and signin manager to use a single instance per request
app.CreatePerOwinContext(ApplicationDbContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);
It looks like this is to access the database for Identity features. My understanding is that a single instance of ApplicationDbContext is created per request and re-used through the entire pipeline. Would it be beneficial to do the same with my own entity framework DbContexts?
For example I created a new file in App_Start/Startup.Data.cs:
public partial class Startup
{
public void ConfigureData(IAppBuilder app)
{
app.CreatePerOwinContext(CreateParkingEntities);
}
protected ParkingEntities CreateParkingEntities()
{
return new ParkingEntities();
}
}
Then in Startup.cs:
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
ConfigureAuth(app);
ConfigureData(app);
}
}
Then I can use the context in my controllers:
private ParkingEntities _db;
public ParkingEntities DbContext
{
get
{
return _db ?? HttpContext.GetOwinContext().Get<ParkingEntities>();
}
private set
{
_db = value;
}
}
I would think if this was standard practice, the entity framework would have some scaffolding for this, but it just creates an instance at the controller level. Is it safe to assume that if DbContext is only accessed from that controller then it would be functionally equivalent to the above implementation and placing it in the Owin pipeline is overkill?
I suppose another use of this approach is a single initialization point for the DbContext, if additional setup is needed.
DbContext is designed to be lightweight, so there isn't much cost to creating a new instance every time you need one. The main costs are re-creating the connection and garbage-collecting all of the instances you are creating.
Note that if you use the Find() method on the DbSets, it will cache the result, so next time you ask for it, it doesn't need to go to the database. If you re-use the same context, you can take advantage of that cache, but if you create a new context, you lose the cache.
If you store the DbContext in an instance member of the controller, then it will only get used for one request, since a new instance of the controller will be created for each request. Just make sure you DON'T put it in a static member - I expect that you would get all kinds of race conditions if you do that.
The main approach to use EF db-context is simple: connect to the db-context, get your data and forget about this db-context object. EF context is IDisposable and closes the connection after dispose (don't forget about using(){}). It means, that you can create EF data-context anywhere in your application when it needs a db-connection. You can create new db-context right inside the controller-action if they are using your db. Everything depends on what is the architecture of your application. If you are sure, that all requests to your app will need many db-operations, I think your solution with db-context per owin-context can be useful.
I used lot of model for connecting to db, in my last project that i worked with C# & entity framework, i created static class for db connecting but i had problem with opening and closing connection for that give me error when more than 10-15 requests come together, i solved it with changing method of connecting to db with i connect now per request and removed all static methods and classes.
Now i want to know,
What is best model for making connection?
Should i close it after every query and open it before using or ...?
A connection in static class is good model (that i don`t need to
create it, every time)?
Is there a good design pattern for this problem?
All of it is for the same question What is the best method for
making database connection (static, abstract, per request, ...)?
For example i working on a sms sender web panel, I should send 100K sms per second, these sms collect with others and make a package that every package have 1~20 sms then i need to send 5K~100K packages per one second and when i send a package i should do these steps:
Update single sms to delivered or not delivered
Update user balance if delivered decrease user balance in useraccounts table
Update number of sms send count in user table
Update number of sms send count in mobile number table
Update number of sms send count in sender number table
Update package for delivered and failed sms in package table
Update package for how thread send this package in package table
Update thread table for how many sms send it by this tread and how many failed
Add account document for this transactions in AccountDocument table
All steps and lot of other things like logs, user interface and monitoring widgets, that should doing and i need DB connection for doing every single of this transactions.
Now, What is best model for connecting to DB? By human request or by thread request or by every single transaction..
answers to your questions:
Close it. .NET does connection pooling for you under the hood.
Create it. use the using (Connection conn = new ....) each time - this way, you'll make the most out of the .NET pooling mechanism.
you can use the .NET ThreadPool (or your own custom one), define the ThreadPool to use solely 10 thread in parallel and Enqueue work items one after another. this way no more then 10 connections will be used in the same time + it'll probably work faster.
More about Custom ThreadPools: Custom ThreadPool Implementation
Per instance.
Here's my suggestion for an architecture:
Create a database table (queue) for pending SMS to be sent out.
each row will contain all the information needed for the sms + the current status.
create a worker process, perhaps a windows service which will sample this table constantly - let's say, each 5 seconds. it will select the TOP ~20 SMS with status = 'pending to be sent' (should be represented as int). and will update the status to 'sending'
each sms will be sent out using a custom threadpool on the windows service side.
in the end of the process, ALL the processed sms status will be updated to 'done' using a CTE (common table expression - you can send a cte with all the sms rows ids that have just been process to do a 'bulk update' to 'done' status).
you could make the status update stored procedure to be the same one as the 'getpending'. this way, you could select-for-update with no lock and make the database work faster.
this way, you can have more than just one processor service running (but then you'll have to loose the nolock).
remember to avoid as much locking as possible.
by the way, this is also good because you could send SMS from any place in your system by simply adding a row to the pending SMS table.
And one more thing, i would not recommend to use entity framework for this, as it has too much going on under the hood. All you need for this kind of task is to simply call 3-4 stored procedures, and that's it. Maybe take a look at Dapper-dot-NET - its a very lightweight MicroDal framework which in most cases works more than 10 times faster than EF (Entity Framework)
1. Should i close it after every query?
.Net does that for you so let it handle it, that's a garbage collector task. So don't bother disposing your objects manually, this is a good answer by Jon Skeet: https://stackoverflow.com/a/1998600/544283. However you could use the using(IDisposable){ } statement to force the GC to do it's work. Here is a nice article about resources reallocation: http://www.codeproject.com/Articles/29534/IDisposable-What-Your-Mother-Never-Told-You-About.
2. A connection in static class is good?
Never make a data context static! Data contexts are not thread safe or concurrent safe.
3. Is there a good design pattern for this problem?
As Belogix mentioned dependency injection and unit of work patterns are great, in fact entity framework is a unit of work itself. DI and UoW are a bit overrated though, it's not easy to implement if it's your first time handling an IoC container which if you're going that path I'd recommend Ninject. One other thing is you don't really need DI if you're not gonna run tests, the awesomeness of these patterns is to decouple, so you can test and mock without sweat.
In-short: If you're gonna run test against your code go for these patterns. If not, I'm providing you an example about how you could share your data context among the services you'd like. This is the answer to your fourth question.
4. What is the best method for making database connection (static, per request)?
Your context service:
public class FooContextService {
private readonly FooContext _ctx;
public FooContext Context { get { return _ctx; } }
public FooContextService() {
_ctx = new FooContext();
}
}
Other services:
public class UnicornService {
private readonly FooContext _ctx;
public UnicornService(FooContextService contextService) {
if (contextService == null)
throw new ArgumentNullException("contextService");
_ctx = contextService.Context;
}
public ICollection<Unicorn> GetList() {
return _ctx.Unicorns.ToList();
}
}
public class DragonService {
private readonly FooContext _ctx;
public DragonService(FooContextService contextService) {
if (contextService == null)
throw new ArgumentNullException("contextService");
_ctx = contextService.Context;
}
public ICollection<Dragon> GetList() {
return _ctx.Dragons.ToList();
}
}
Controller:
public class FantasyController : Controller {
private readonly FooContextService _contextService = new FooContextService();
private readonly UnicornService _unicornService;
private readonly DragonService _dragonService;
public FantasyController() {
_unicornService = new UnicornService(_contextService);
_dragonService = new DragonService(_contextService);
}
// Controller actions
}
Second thoughts (almost an edit):
If you need your context not to create the proxies for your entities therefore not having lazy loading either, you could overload your context service as follows:
public class FooContextService {
private readonly FooContext _ctx;
public FooContext Context { get { return _ctx; } }
public FooContextService() : this(true) { }
public FooContextService(bool proxyCreationEnabled) {
_ctx = new FooContext();
_ctx.Configuration.ProxyCreationEnabled = proxyCreationEnabled;
}
}
NOTE:
If you set the proxy creation enabled to false you will not have lazy loading out of the box.
If you have api controllers you don't want to deal with any full blown object graph.
EDIT:
Some reading first:
This link relates to a pre-release version of EF6: Entity Framework and Async.
Scott Allen posted about this in his blog: Async in Entity Framework 6.0.
If you're going to use Unit of Work I'd recommend to read this: Make the DbContext Ambient with UnitOfWorkScope.
Darin Dimitrov's answer on Do asynchronous operations in ASP.NET MVC use a thread from ThreadPool on .NET 4.
Get this done:
(_context as IObjectContextAdapter).ObjectContext.Connection.Open();
This is a great article about Managing Connections and Transactions.
Entity framework exposes EntityConnection through the Connection property. Read as: public sealed class EntityConnection : DbConnection.
Considerations for managing connections: (taken from previous link)
The object context will open the connection if it is not already open before an operation. If the object context opens the connection during an operation, it will always close the connection when the operation is complete.
If you manually open the connection, the object context will not close it. Calling Close or Dispose will close the connection.
If the object context creates the connection, the connection will always be disposed when the context is disposed.
In a long-running object context, you must ensure that the context is disposed when it is no longer required.
Hope it helps.
I think per request scales the best. Use a thread-safe connection pool and make the connection scope coincide with the unit of work. Let the service that's responsible for transactional behavior and units of work check out the connection, use it, and return it to the pool when the unit of work is either committed or rolled back.
UPDATE:
10-12 seconds to commit a status update? You've done something else wrong. Your question as written is not sufficient to provide a suitable answer.
Daily NASDAQ volume is 1.3B transactions, which on an 8 hour day works out to ~45K transactions per second. Your volume is 2X that of NASDAQ. If you're trying to do it with one machine, I'd say that NASDAQ is using more than one server.
I'd also wonder if you could do without that status being updated using ACID. After all, Starbucks doesn't use two-phase commit. Maybe a better solution would be to use a producer/consumer pattern with a blocking queue to update those statuses when you can after they're sent.