Answer the question
In order to leave comments, you need to log in
How to isolate code execution by multiple threads?
Simplified example:
asp.net mvc application
Let's say the user makes an order
We have the OrderService class - for placing an order and UserService for operations on the cash balance
. We place an order by making an ajax post request from the client to the controller (HomeController) from which the OrderService is already twitching
public class OrderService
{
private readonly UserService _userService;
private readonly DbContext _dbContext;
public OrderService(DbContext dbContext, UserService userService)
{
_userService = userService;
_dbContext = dbContext;
}
public int AddOrder(decimal totalSum)
{
var order = new OrderEntity
{
TotalSum = totalSum
};
var balance = _userService.GetBalance();
// проверяем баланс
if (balance < order.TotalSum)
{
throw new Exception("Not enough money");
}
// списываем деньги
_userService.OperateBalance(-order.TotalSum);
_dbContext.Set<OrderEntity>().Add(order);
_dbContext.SaveChanges();
return order.Id;
}
}
public class UserService
{
private readonly DbContext _dbContext;
public UserService(DbContext dbContext)
{
_dbContext = dbContext;
}
public decimal GetBalance()
{
return _dbContext.Set<UserEntity>().FirstOrDefault(x => x.Id == userId)?.Balance;
}
public void OperateBalance(decimal amount)
{
var user = _dbContext.Set<UserEntity>().FirstOrDefault(x => x.Id == userId);
if (user != null)
{
user.Balance += amount;
_dbContext.SaveChanges();
}
}
}
public class HomeController : Controller
{
private readonly IOrderService _service;
public HomeController(IOrderService service)
{
_service = service;
}
[HttpPost]
public JsonResult PostOrder(decimal totalSum)
{
var result = _service.AddOrder(totalSum);
return Json(result);
}
}
$.post('/Home/PostOrder', { totalSum: 150 })
.success(function(res) {
console.info('res1', res);
});
Answer the question
In order to leave comments, you need to log in
First, if the OrderService is not resolved as a singleton, then a separate service instance will be created for each request, i.e. there will not be two threads per method.
Second, if it resolves as a singleton, then you're in trouble. inside dbContext there will be one for all requests, and it is better to create it on a new one for each request.
Third, in order to avoid two simultaneous requests from one client, you need to disable the button and show the preloader until a response is received.
And fourthly, if you want to get the balance before another request adds something there, then in AddOrder use transactions with a sufficient level of change lock.
Is this generally normal practice? Are there any other options?
Didn't find what you were looking for?
Ask your questionAsk a Question
731 491 924 answers to any question