Enable ASP.Net Core Session Locking? - c#

According to the ASP.Net Core docs, the behaviour of the session state has changed in that it is now non-locking:
Session state is non-locking. If two requests simultaneously attempt to modify the contents of a session, the last request overrides the first. Session is implemented as a coherent session, which means that all the contents are stored together. When two requests seek to modify different session values, the last request may override session changes made by the first.
My understanding is that this is different to the behaviour of the session in the .Net Framework, where the user's session was locked per request so that whenever you read from/wrote to it, you weren't overwriting another request's data or reading stale data, for that user.
My question(s):
Is there a way to re-enable this per-request locking of the user's session in .Net Core?
If not, is there a reliable way to use the session to prevent duplicate submission of data for a given user? To give a specific example, we have a payment process that involves the user returning from an externally hosted ThreeDSecure (3DS) iFrame (payment card security process). We are noticing that sometimes (somehow) the user is submitting the form within the iFrame multiple times, which we have no control over. As a result this triggers multiple callbacks to our application. In our previous .Net Framework app, we used the session to indicate if a payment was in progress. If this flag was set in the session and you hit the 3DS callback again, the app would stop you proceeding. However, now it seems that because the session isn't locked, when these near simultaneous, duplicate callbacks occur, thread 'A' sets 'payment in progress = true' but thread 'B' doesn't see that in time, it's snapshot of the session is still seeing 'payment in progress = false' and the callback logic is processed twice.
What are some good approaches to handling simultaneous requests accessing the same session, now that the way the session works has changed?

The problem that you have faced with is called Race Condition (stackoverflow, wiki). To cut-through, you'd like to get exclusive access to the session state, you can achieve that in several ways and they highly depend on your architecture.
In-process synchronization
If you have a single machine with a single process handling all requests (for example you use a self-hosted server, Kestrel), you may use lock. Just do it correctly and not how #TMG suggested.
Here is an implementation reference:
Use single global object to lock all threads:
private static object s_locker = new object();
public bool Process(string transaction) {
lock (s_locker) {
if(!HttpContext.Session.TryGetValue("TransactionId", out _)) {
... handle transaction
}
}
}
Pros: a simple solution
Cons: all requests from all users will wait on this lock
use per-session lock object. Idea is similar, but instead of a single object you just use a dictionary:
internal class LockTracker : IDisposable
{
private static Dictionary<string, LockTracker> _locks = new Dictionary<string, LockTracker>();
private int _activeUses = 0;
private readonly string _id;
private LockTracker(string id) => _id = id;
public static LockTracker Get(string id)
{
lock(_locks)
{
if(!_locks.ContainsKey(id))
_locks.Add(id, new LockTracker(id));
var res = _locks[id];
res._activeUses += 1;
return res;
}
}
void IDisposable.Dispose()
{
lock(_locks)
{
_activeUses--;
if(_activeUses == 0)
_locks.Remove(_id);
}
}
}
public bool Process(string transaction)
{
var session = HttpContext.Session;
var locker = LockTracker.Get(session.Id);
using(locker) // remove object after execution if no other sessions use it
lock (locker) // synchronize threads on session specific object
{
// check if current session has already transaction in progress
var transactionInProgress = session.TryGetValue("TransactionId", out _);
if (!transactionInProgress)
{
// if there is no transaction, set and handle it
HttpContext.Session.Set("TransactionId", System.Text.Encoding.UTF8.GetBytes(transaction));
HttpContext.Session.Set("StartTransaction", BitConverter.GetBytes(DateTimeOffset.UtcNow.ToUnixTimeSeconds()));
// handle transaction here
}
// return whatever you need, here is just a boolean.
return transactionInProgress;
}
}
Pros: manages concurrency on the session level
Cons: more complex solution
Remember that lock-based option will work only when the same process on the webserver handling all user's requests - lock is intra-process synchronization mechanism! Depending on what you use as a persistent layer for sessions (like NCache or Redis), this option might be the most performant though.
Cross-process synchronization
If there are several processes on the machine (for example you have IIS and apppool is configured to run multiple worker processes), then you need to use kernel-level synchronization primitive, like Mutex.
Cross-machine synchronization
If you have a load balancer (LB) in front of your webfarm so that any of N machines can handle user's request, then getting exclusive access is not so trivial.
One option here is to simplify the problem by enabling the 'sticky session' option in your LB so that all requests from the same user (session) will be routed to the same machine. In this case, you are fine to use any cross-process or in-process synchronization option (depends on what you have running there).
Another option is to externalize synchronization, for example, move it to the transactional DB, something similar to what #HoomanBahreini suggested. Beware that you need to be very cautious on handling failure scenarios: you may mark your session as in progress and then your webserver which handled it crashed leaving it locked in DB.
Important
In all of these options you must ensure that you obtain lock before reading the state and hold it until you update the state.
Please clarify what option is the closest to your case and I can provide more technical details.

Session is designed to store temporary user data among multiple requests, a good example is login-state... without session you would have to login to stackoverflow.com every time you open a new question... but the website remembers you, because your send them your session state inside a cookie. According to Microsoft:
The session data is backed by a cache and considered ephemeral data.
The site should continue to function without the session data.
Critical application data should be stored in the user database and
cached in session only as a performance optimization.
It is quite simple to implement a locking mechanism to solve your mutex issue, however the session itself is not a reliable storage and you may loose its content at any time.
How to identify duplicate payments?
The problem is you are getting multiple payment requests and you want to discard the duplicate ones... what's your definition of a duplicate payment?
Your current solution discard the second payment while a first one is in progress... let's say your payment takes 2 seconds to complete... what will happen if you receive the duplicate payment after 3 seconds?
Every reliable payment system includes a unique PaymentId in their request... what you need to do is to mark this PaymentId as processed in your DB. This way you won't process the same payment twice, no matter when the duplicate request arrives.
You can use a Unique Constraint on PaymentId to prevent duplicate payments:
public bool ProcessPayment(Payment payment) {
bool res = InsertIntoDb(payment);
if (res == false) {
return false; // <-- insert has failed because PaymentId is not unique
}
Process(payment);
return true;
}
Same example using lock:
public class SafePayment {
private static readonly Object lockObject = new Object();
public bool ProcessPayment(Payment payment) {
lock (lockObject) {
var duplicatePayment = ReadFromDb(payment.Id);
if (duplicatePayment != null) {
return false; // <-- duplicate
}
Process(payment);
WriteToDb(payment);
return true;
}
}
}

Related

Why isn't my lazy loading of an expensive operation in multithreaded environment working?

I have an ASP.NET web app, which calls an expensive operation and needs to cache the data. The call to the operation needs to be made only one time, even if there are concurrent requests.
The idea is that I keep the data in a ConcurrentDictionary. The first time any request access the dictionary, a Lazy record is inserted to defer the work for later. Any subsequent requests should get back the same record. Also the expensive operation uses await because of usage of HttpClient.
I tried to implement this with the following code
private static readonly ConcurrentDictionary<Guid, Lazy<Task<List<ProductsList>>>> cache =
new ConcurrentDictionary<Guid, Lazy<Task<List<ProductsList>>>>();
public async Task<List<ProductsList>> Get(AnalysisParams aParams, string refUrlApi)
{
return await cache.GetOrAdd(aParams.Project_ID, (pid) => new Lazy<Task<List<ProductsList>>>(
async () => await Task.Run(async() => await Utils.GetProductsList(aParams, refUrlApi))
)).Value;
}
However when I check my logs, I can see that the expensive operation is called multiple times through the day instead of once. The instance where the web app is running is not restarted according to the admin.
Maybe I have messed up with the async/await? How can I achieve what I need?

User session in background task in ASP.NET Core

I learned that the preferred ASP.NET-Core-way for background tasks is a hosted service.
Is there any way to pass the (user) session to this background worker? Usually the session is part of the HttpContext which will not be available in the background task...
I know that I could persist data by writing to the database but I'd also like to cache some data in memory.
If this is all happening in-process, then you should be able to just pass the ISession object directly to your background service and have it interact with the user’s session without the user’s HttpContext having to be around.
The default session implementation is using the distributed cache to persist the information stored in the session. Each session object is then only interacted by with a session key that is stored in a user cookie. When the session object is being created, no direct or indirect reference to the HttpContext is being passed. The session store itself also does not access the HttpContext in some other way. The distributed cache itself is also independent of the context and also the DI service scope.
So at least in theory, this should work just fine. You can use the ISession object to modify the session and the next time the user makes a request with their session id, the updated information will be there waiting for them.
There is no guarantee the user session will exist when executing the background task. Encapsulate the data your task requires from the user session and pass it to the background task.
As you know session is based on this user request. User owns the session!
So when we are talking about session, actually we are pointing to the end-user-request received from the client! Imagine a situation that you have a background task in an aspnetcore-based micro-service with no user requests. Never ever you wont see any sessions to capture because there is no user to send any request.
In a normal sunny day, the probability of user session existence inside a background task is very low.
BUT!
If you have a background service that you want to use it as a cache, you should execute cache read/write operations per user request. I highly recommend you to avoid using HttpContext inside your background task, because your task will be non-extendable, tightly-coupled with http infrastructure.
There is a simple SAMPLE :D to be more clarified:
public interface ICache {
Task Write(string uniqueIdentifier, object data);
Task<object> Read(string uniqueIdentifier);
}
public class BackgroundTaskBasedCache : ICache {
public void Init()
{
//Initialize your background operations.
}
//IO bound
public async Task Write(string sessionId, object data)
{
//write inside your cache.
}
public async Task<object> Read(string sessionId)
{
//read from your cache.
return new object();//for test.
}
}
startup.cs:
//this will add a signleton background task. (you can do it manually or using other tools/strategies.
services.AddSingleton<ICache, BackgroundTaskBasedCache>();
inside your controller:
{
public TestController(ICache cache, IHttpContextAccessor){//fill properties}
public async Task<IActionResult> ExecuteSomeRequestAction()
{
await cache.Write(httpContextAccessor.HttpContext.SessionId, data);
}
}
hope to understand and best regards :)

Async/await and resource access

I’m wondering how to implement resource access nicely using async/await. I have singleton service in web application that is acting as a proxy to LDAP and have to buffer all data on first access – all invocation after that is done via cache but after some time cache is invalidated and data should be get again. Now my implementation looks like this but it is not meet my requirements
public async Task<string> GetUserDisplayName(string username)
{
var users = await GetCachedUsers();
// code using users from cache
}
private async Task<IEnumerable<LdapUser>> GetCachedUsers()
{
var users = _Cache.Get<IEnumerable<LdapUser>>();
if (users == null)
{
users = await _Connector.GetAllUsers();
_Cache.Add(users, TimeSpan.FromHours(USER_CACHE_VALID_HOURS));
}
return users;
}
I’m wondering how to implement this in this way that when couple request go to the service first time they should be awaited on the same task but not blocked and download from LDAP should go only once. I could do this traditionally and lock the resource but that threads will be blocked and I want them to back to threadpool in async way like in async/wait pattern.
SemaphoreSlim has a WaitAsync method that will let you create a critical section in asynchronous code. You can use that semaphore to prevent multiple invocations of the method from generating the value together without actually blocking any of the threads.

What is the best method for making database connection (static, abstract, per request, ...)?

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.

Implementing Singleton across requests to HttpHandler

I am attempting to create a singleton service that is used to process incoming requests to an HttpHandler. At the moment the service is being instantiated on every request. I make a call to the static class that holds an instance of the service, implemented as a singleton as below:
public static class ServerApplication {
static Service instance = null;
static readonly object padlock = new object();
/// <summary>
/// Service singleton.
/// </summary>
public static Service Service {
get {
lock (padlock) {
if (instance == null) {
instance = new Service();
}
return instance;
}
}
}
And access it using a call as below in the HttpHandler:
ServerApplication.Service.Process(request);
I have set a breakpoint on the instance = new Service(); line and with multiple requests the
breakpoint is triggered per request.
My aim is a service that exists across requests as it loads and caches lots of data from files and databases that is reused with most requests.
Can anyone see what is going wrong?
A couple of things:
If it's a multiprocessor box, technically, you should mark the shared service instance with the "volatile" keyword or use a call to MemoryBarrier (see http://blogs.msdn.com/brada/archive/2004/05/12/130935.aspx). You didn't specify architecture, so hard to say if this is really the issue, but better safe than sorry.
You should implement a double-check lock (eg, check for null both before and after acquiring the lock on "padlock"). This way you're doing a much cheaper comparison instead of acquiring a lock on all the subsequent reads.
That should cover you on the concurrency fronts. It's also possible (though less likely) that your AppDomain is being unloaded between requests (ie, you wrote a file inside the web directory causing ASP.NET to think your app is stale), which would cause the statics to be reset.
HTTP is designed to make several concurrent connections, I don't know that you'd want to break this, unless you make very few connections on page loads. That said, perhaps you could keep the HttpHandler in the Session?
Generally speaking, if you want a singleton - cannot see if its necessary i usually implement it this way: http://www.vikingworks.dk/page/Creating-a-Singleton-Pattern-i-C.aspx

Categories