Преобразовать обычный метод в асинхронный - PullRequest
0 голосов
/ 01 мая 2018

У меня есть API, который отвечает за вставку данных текстовых сообщений в базу данных. Это происходит путем синхронного вызова репозитория, который, я думаю, может быть реализован асинхронным способом. Как я могу добиться этого? Или что может быть лучшим способом справиться с этим сценарием. Пример фрагмента кода высоко ценится, так как я все еще продолжаю работать над .NET.

апи:

public IHttpActionResult SendSMSNotification([FromBody] SMSNotification smsNotification)
    {
        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }            
        _service.SendSMS(smsNotification);

        return Ok();
    }

Услуги:

internal void SendSMS(SMSNotification smsNotification)
    {
        _repository.Notify(_mapperService.GetSMSNotification(smsNotification));
    }

картограф:

public SMSNotification GetSMSNotification(SMSNotification message)
    {
        return AutoMapper.Mapper.Map<SMSNotification>(message); 
    }

репо:

public virtual bool Notify(SMSNotification request)
    {
        using (var sql = _sqlMapper.CreateCommand('Database', 'Stored proc'))
        {
            sql.AddParam("@fMessage", request.Message);
           //..............
           //.............. more params
            var retvalParamOutput = sql.AddOutputParam("@fRetVal", System.Data.SqlDbType.Int);
            sql.Execute();
            return retvalParamOutput.GetSafeValue<int>() == 1;
        }
    }

sql здесь пользовательская вещь, и она имеет следующие методы:

  public static int Execute(this IDataCommand @this);
        [AsyncStateMachine(typeof(<ExecuteAsync>d__1))]
        public static Task<int> ExecuteAsync(this IDataCommand @this);

1 Ответ

0 голосов
/ 02 мая 2018

Изменение блокировки, обычно связанной с вводом-выводом вызова (например, работа с базой данных, сеть или файловая система), на асинхронность может улучшить масштабирование вашего приложения.

Это влияет на ваш API. То есть вам нужно ожидать асинхронных вызовов вплоть до самого верхнего вызова, в противном случае где-то будет блокироваться, и вы просто потеряете преимущество вызова асинхронного API.

Чтобы продемонстрировать это, давайте начнем снизу при вызове репозитория, поскольку это, возможно, дорогостоящая операция блокировки, которая может быть сделана асинхронной. Мы изменяем sql.Execute, чтобы использовать вместо него версию ExecutAsync асинхронной версии:

репо:

public virtual async Task<bool> Notify(SMSNotification request)
{
    using (var sql = _sqlMapper.CreateCommand('Database', 'Stored proc'))
    {
        sql.AddParam("@fMessage", request.Message);
       //..............
       //.............. more params
        var retvalParamOutput = sql.AddOutputParam("@fRetVal", System.Data.SqlDbType.Int);
        await sql.ExecuteAsync();
        return retvalParamOutput.GetSafeValue<int>() == 1;
    }
}

Теперь здесь мы должны изменить сигнатуру метода, чтобы он возвращал задачу, заключающую в себе результат bool.

Мы также помечаем метод как асинхронный, так что мы можем использовать оператор «ожидание» далее. Без этого нам пришлось бы сделать больше рефакторинга, чтобы самим манипулировать и возвращать результат Task, но модификатор async и ключевое слово «await» позволяют компилятору сделать это за нас, а остальная часть нашего кода выглядит в основном так: нормальный.

Вызов mapper на самом деле не нуждается в изменении:

картограф:

public SMSNotification GetSMSNotification(SMSNotification message)
{
    return AutoMapper.Mapper.Map<SMSNotification>(message); 
}

Сервисный вызов теперь делает вызов асинхронного метода, поэтому, поскольку мы хотим ожидать, а не блокировать этот асинхронный вызов, мы должны также изменить этот ранее недействительный метод на асинхронный метод. Обратите внимание, что мы изменили его с «void» на «async Task»; вы МОЖЕТЕ пометить метод void как «async void», но он предназначен для обхода обработчиков событий в приложениях Windows Forms и WPF; в любом другом случае вы хотите изменить метод «void» на «async Task» при его асинхронном выполнении.

Услуги:

internal async Task SendSMS(SMSNotification smsNotification)
{
    await _repository.Notify(_mapperService.GetSMSNotification(smsNotification));
}

Затем, наконец, наш вызов API можно сделать асинхронным и ожидать нашего вызова службы:

апи:

public async Task<IHttpActionResult> SendSMSNotification([FromBody] SMSNotification smsNotification)
{
    if (!ModelState.IsValid)
    {
        return BadRequest(ModelState);
    }            
    await _service.SendSMS(smsNotification);

    return Ok();
}

Иногда рекомендуется после такого рефакторинга переименовать методы, чтобы они заканчивались в «Асинхронном» по соглашению; однако я не думаю, что это действительно обязательно, так как большая часть поверхности .NET API становится асинхронной, теперь она почти избыточна.

Стоит подумать об асинхронных / ожидающих вещах; Я постарался сделать пример относительно коротким. Но я надеюсь, что это, по крайней мере, поможет вам начать.

...