Доступ к асинхронному методу из базового класса - PullRequest
0 голосов
/ 02 июня 2019

У меня есть проект .NET Core 2.2 Web Api, где я пытаюсь сделать все, используя подход async / await. У меня есть контроллер под названием «UserController». У меня есть методы в моем "UserController", где мне нужно получить доступ к LoggedInUserId. Итак, для этого я создал «BaseController», от которого «UserController» унаследует.

BaseController.cs

public abstract class BaseController : ControllerBase
{
    public int LoggedInUserId
    {
        get
        {
           Task<int> task = Task.Run(async () => await GetLoggedInUserId());
           return task.Result;
        }
    }
}

В "BaseController" есть частный метод, называемый "GetLoggedInUserId ()", который будет вызывать базу данных (именно поэтому этот метод должен быть асинхронным) и извлекать нужную мне информацию.

Итак, после понимания, вот мой "UserController"

UserController.cs

[Route("api/[controller]")]
[ApiController]
public class UsersController : BaseController
{
    public UsersController() 
    {

    }

    [HttpPost("create")]
    public async Task<ActionResult<User>> Create([FromBody] userCreate)
    {
        _userService.CreateUser(userCreate, LoggedInUserId);
    }
}

Как вы видите, я обращаюсь к свойству "LoggedInUserId" из "BaseController", но меня беспокоит то, что, поскольку свойство "LoggedInUserId" в "BaseController" возвращает "task.Result", то оно не является действительно асинхронным .

Итак, я подумал о другом способе, заключающемся в том, чтобы удалить свойство «LoggedInUserId» из «BaseController» и сделать метод «GetLoggedInUserId ()» открытым методом вместо частного и получить к нему доступ следующим образом:

UserController.cs

_userService.CreateUser(userCreate, await GetLoggedInUserId());

Итак, мои вопросы таковы:

  1. Можно ли считать оба этих подхода правильными и соответствуют ли они асинхронному / ожидающему способу выполнения вещей?
  2. Оба эти подхода выполняют одно и то же?
  3. Есть ли у них какие-либо недостатки любого из этих двух подходов?
  4. Если кто-либо увидит какие-либо недостатки в этих подходах, вы можете предложить лучший / более чистый способ достижения моей цели.

Ответы [ 3 ]

2 голосов
/ 02 июня 2019
  1. Будут ли оба эти подхода считаться правильными и соответствуют ли они асинхронному / ожидающему способу ведения дел?

Нет, первый подходневерно, если у вас нет явных причин для использования Task.Result, и даже тогда Task.Run не требуется для вызова метода, объявленного с Task.

Оба эти подхода выполняют одно и то же?

Нет, первый метод создает ненужный поток для синхронной блокировки на нем.Если бы вы работали в среде, которая использует SynchronizationContext (например, классический ASP.NET, WinForms, Xamarin или WPF), вы оказались бы в тупике.Второй подход, однако, является правильным способом сделать асинхронный вызов.В обоих случаях вы получите идентификатор пользователя, по крайней мере, на данный момент.

Есть ли у них какие-либо недостатки любого из этих двух подходов?

Да, как уже упоминалось выше, первый подход только приводит к пустой трате ресурсов.

Если кто-то видит недостатки в этих подходах, можете ли вы предложить лучший / более чистый способ достижения моей цели.

Ну, вы не упомянули, что вы используете для аутентификации /авторизации, но если вы используете ASP.NET Core Identity, он уже предоставляет вам эту функциональность через класс UserManager<TUser>.В противном случае вы могли бы использовать промежуточное программное обеспечение, которое считывает запрос и добавляет необходимые данные в контроллер.

2 голосов
/ 02 июня 2019

Несколько сообщений о том, что не так с этим. Посмотрим, как можно это исправить:

public abstract class BaseController : ControllerBase
{
    public Task<int> LoggedInUserId()
    {
        return await GetLoggedInUserId();
    }
}

или просто сделайте GetLoggedInUserId () доступным. Вы получаете смысл. А потом:

[HttpPost("create")]
public async Task<ActionResult<User>> Create([FromBody] userCreate)
{
     int loggedInUserId = await LoggedInUserId();
    _userService.CreateUser(userCreate, loggedInUserId);
    ...
}
2 голосов
/ 02 июня 2019

Будут ли оба эти подхода считаться правильными и соответствуют ли они асинхронному / ожидающему способу выполнения вещей?

Нет. Использование Task.Run и Result не использует async / await, как задумано. Task.Run часть лишняя.

Оба эти подхода выполняют одно и то же?

Они оба получают зарегистрированного пользователя. Тем не менее, подход на основе Result блокирует поток при этом.

Есть ли у них какие-либо недостатки любого из этих двух подходов?

Да. Подход на основе Result блокирует поток, что ограничивает вашу масштабируемость.

<Ч />

Мне кажется, есть лучший способ сделать это. Я не совсем знаком с конвейером ASP.NET Core, но должен быть способ асинхронной обработки аутентификации и получения идентификатора пользователя, вошедшего в систему, еще до того, как контроллер будет построен. Затем вы можете выставить его как свойство, так как к тому времени он уже загружен.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...