Вызов asyn c stati c метода из Asp. Net контроллера Web Api - PullRequest
0 голосов
/ 06 февраля 2020

У меня есть синхронный 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 на основной метод, передаваемый этим методам, он начал работать. Это решение хорошо?
...