У меня есть синхронный API [HttpPost], который я вызываю из клиентского приложения. Во время его выполнения, когда возникают определенные условия c, я хочу, чтобы он вызывал метод stati c асинхронно - мне не нужно ждать его результата в методе main. Вот мой метод API:
public class ProcessController : ApiController
{
private Models.DbModel db = new Models.DbModel();
public IHttpActionResult EditProcess(string token, int id, int UserId, JDE_Processes item, bool UseServerDates = true)
{
if (token != null && token.Length > 0)
{
var tenants = db.JDE_Tenants.Where(t => t.TenantToken == token.Trim());
if (tenants.Any())
{
var items = db.JDE_Processes.AsNoTracking().Where(u => u.TenantId == tenants.FirstOrDefault().TenantId && u.ProcessId == id);
if (items.Any())
{
item.CreatedOn = items.FirstOrDefault().CreatedOn;
if (items.FirstOrDefault().StartedOn != null)
{
//It has already had a date. Keep it
item.StartedOn = items.FirstOrDefault().StartedOn;
}
else
{
if (item.StartedOn != null && UseServerDates)
{
//this has just been started. Must have been planned before. Replace user's date
item.StartedOn = DateTime.Now;
item.LastStatusBy = UserId;
item.LastStatusOn = DateTime.Now;
//if ActionType of this process requires closing all previous processes of the type, do it now
Utilities.CompleteAllProcessesOfTheTypeInThePlace((int)item.PlaceId, (int)item.ActionTypeId, id, UserId, "Test"); <-- HERE
}
}
string descr = "Edycja zgłoszenia";
JDE_Logs Log = new JDE_Logs { UserId = UserId, Description = descr, TenantId = tenants.FirstOrDefault().TenantId, Timestamp = DateTime.Now, OldValue = new JavaScriptSerializer().Serialize(items.FirstOrDefault()), NewValue = new JavaScriptSerializer().Serialize(item) };
db.JDE_Logs.Add(Log);
db.Entry(item).State = EntityState.Modified;
try
{
db.SaveChanges();
}
catch (DbUpdateConcurrencyException)
{
if (!JDE_ProcessesExists(id))
{
return NotFound();
}
else
{
throw;
}
}
}
}
}
return StatusCode(HttpStatusCode.NoContent);
}
}
А вот асинхронный метод, который я вызываю:
public static class Utilities
{
private static Models.DbModel db = new Models.DbModel();
public async static Task CompleteAllProcessesOfTheTypeInThePlace(int thePlace, int theType, int excludeProcess, int UserId, string reasonForClosure = null)
{
bool? requireClosing = db.JDE_ActionTypes.Where(i => i.ActionTypeId == theType).FirstOrDefault().ClosePreviousInSamePlace;
if(requireClosing == null) { requireClosing = false; }
if ((bool)requireClosing)
{
IQueryable<JDE_Processes> processes = null;
processes = db.JDE_Processes.Where(p => p.PlaceId == thePlace && p.ActionTypeId==theType && p.ProcessId<excludeProcess && (p.IsCompleted == false || p.IsCompleted == null) && (p.IsSuccessfull == false || p.IsSuccessfull == null));
if (processes.Any())
{
foreach(var p in processes)
{
CompleteProcessAsync(db,(int)processes.FirstOrDefault().TenantId, p, UserId, reasonForClosure);
}
}
}
}
public async static void CompleteProcessAsync(int tenantId, JDE_Processes item, int UserId, string reasonForClosure = null)
{
string OldValue = new JavaScriptSerializer().Serialize(item);
item.FinishedOn = DateTime.Now;
item.FinishedBy = UserId;
item.IsActive = false;
item.IsCompleted = true;
item.IsFrozen = false;
item.LastStatus = (int)ProcessStatus.Finished;
item.LastStatusBy = UserId;
item.LastStatusOn = DateTime.Now;
var User = db.JDE_Users.AsNoTracking().Where(u => u.UserId == UserId).FirstOrDefault();
if (reasonForClosure == null)
{
item.Output = $"Przymusowe zamknięcie zgłoszenia przez {User.Name + " " + User.Surname}";
}
else
{
item.Output = reasonForClosure;
}
JDE_Logs Log = new JDE_Logs { UserId = UserId, Description = "Zamknięcie zgłoszenia", TenantId = tenantId, Timestamp = DateTime.Now, OldValue = OldValue, NewValue = new JavaScriptSerializer().Serialize(item) };
db.JDE_Logs.Add(Log);
db.Entry(item).State = EntityState.Modified;
db.SaveChanges();
}
}
У меня есть 3 проблемы (или больше сомнений) с моим кодом:
- Поскольку Utilities.CompleteAllProcessesOfTheTypeInThePlace () не ожидается, я предполагаю, что он запускается в некотором фоновом потоке. Я имею в виду, что EditProcess () не дожидается его завершения sh, верно?
- Обычно я использую Task.Run (() => action ()) для запуска чего-либо в фоновом потоке, я не знаю, хорошая ли это практика или распространенная ошибка, меня просто так учили , В этом случае, однако, метод не будет вызываться вообще, если я попытаюсь запустить его из Task.Run (). Почему?
- Я получаю " SqlException: новая транзакция не разрешена, поскольку в сеансе выполняются другие потоки " в db.SaveChanges () в CompleteProcessAsyn c, вероятно, потому что я использовал отдельный dbContext, созданный в фоновом потоке. Когда я заменил этот отдельный dbContext на основной метод, передаваемый этим методам, он начал работать. Это решение хорошо?