Как я могу вызвать метод Async из атрибута фильтра в ASP.NET MVC5

Я пытаюсь сделать запрос async/await из моего пользовательского FilterAttribute, показанного ниже. У меня проблема в том, что это MVC5 и нет асинхронного базового класса для атрибутов фильтра, о которых я знаю, поэтому мне приходится использовать Task для достижения того же результата. Я знаю, что использование Task может повлиять на производительность, но я могу придумать любой другой способ обойти это.

Метод, с которым я хочу сделать async/await вызов, это _authService.IsUserSessionValid

Мне нужно сделать вызов асинхронного метода, который обращается к базе данных и возвращает значение. Я не могу этого сделать, поэтому я завернул вызов в Task. Я понимаю, что OnActionExecuting вызывается дважды, а filterContext.Result не перенаправляет пользователя на действие "SignOut", как я думал. Как я могу это исправить ?

public class SingleSessionValidationFilterAttribute : ActionFilterAttribute
    {

        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            var _authService = (IAuthService)DependencyResolver.Current.GetService(typeof(IAuthService));
            var _formsAuthenticationHelper = (IFormsAuthenticationHelper)DependencyResolver.Current.GetService(typeof(IFormsAuthenticationHelper));

            var currentUserId = _formsAuthenticationHelper.GetLoggedInUserId();
            var currentCookieId = HttpContext.Current.Request.Cookies["CookieKey"]?.Value;
            var task = Task.Run(
                async () => _authService.IsUserSessionValid(new UserSessionValidityCheckerViewModel()
                {
                    CookieId = currentCookieId,
                    UserId = currentUserId
                }));

            task.Wait();

            if (task.Result.IsCompleted)
            {
                var value = task.Result.Result;
                if (!value)
                {
                    filterContext.Result = new System.Web.Mvc.RedirectToRouteResult(
                        new RouteValueDictionary
                        {
                            {"action", "SignOut"},
                            {"controller", "Account"}
                        });
                }
            }

        }

person eagercoder    schedule 31.01.2020    source источник
comment
Внутри вашей асинхронной лямбды ничего не ожидается.   -  person Johnathan Barclay    schedule 31.01.2020
comment
Это IsUserSessionValid действительно асинхронно или это только вы заворачиваете его в Task.Run? Что за история стоит за этим?   -  person Wiktor Zychla    schedule 31.01.2020
comment
@WiktorZychla Я создаю способ отслеживания сеанса пользователя, проект довольно старый и не использует IdentityServer для аутентификации. Таким образом, для одного сеанса, когда пользователь входит в учетную запись (экземпляр 1), создается файл cookie и сохраняется в файле cookie HttpContext, а также база данных для идентификатора пользователя, когда тот же пользователь входит в другое место (экземпляр 2), им разрешено входить в систему, но база данных обновляется новым файлом cookie. Поэтому, если пользователь пытается использовать предыдущий экземпляр, например, нажать кнопку, атрибут фильтра проверяет каждое действие, если файл cookie действителен, а если нет, выходит   -  person eagercoder    schedule 31.01.2020
comment
@WiktorZychla и да, IsUserSession — это ожидаемая асинхронная задача.   -  person eagercoder    schedule 31.01.2020
comment
вам не нужно слово асинхронный в вашем Task.Run(); нет ожидаемой задачи, поэтому она все равно будет выполняться синхронно.   -  person Jawad    schedule 31.01.2020
comment
Невозможно иметь асинхронный вызов в фильтре, не рискуя взаимоблокировкой. Что вы можете сделать, так это обойти эту проблему. здесь.   -  person Wiktor Zychla    schedule 31.01.2020
comment
Что такое IAuthService? Какова подпись IsUserSessionValid и каково определение его типа результата?   -  person Stephen Cleary    schedule 31.01.2020


Ответы (1)


Если _authService.IsUserSessionValid возвращает Task<bool>, вы можете написать

await task; // awaits the task, thus making it asynchronous

вместо

task.Wait(); // this will block further execution until the task completes

после этого вы можете проверить результат и перенаправить.

person Sagar Agrawal    schedule 31.01.2020