Расширение задач для сервисных вызовов Cater App Wide - PullRequest
0 голосов
/ 24 мая 2018

Я работаю в xamarin и пытаюсь использовать все сервисы одним способом.Для этого я написал TaskExtension.Чтобы с каждой страницы приложения я мог вызывать этот метод расширения.Это должно отключить кнопки, показать экран загрузки, обработку ответов и обслужить обработку исключений из одной точки.Я прилагаю свой код ниже.Вам нужны ваши экспертные мнения по этому решению

Вот мой класс расширения

public static class TaskExtensions
{
    public static async Task<ResultViewModel<U>> ExecuteAsyncOperation<U>(this Task<HttpResponseMessage> operation, object sender = null)
    {
        ResultViewModel<U> resultModel = new ResultViewModel<U>();
        Button button = BeforeAsyncCall(sender);
        try
        {
            await BackgroundOperation(operation, resultModel);
        }
        catch (Exception ex)
        {
            resultModel.Status = HttpStatusCode.InternalServerError;
            resultModel.Errors = new List<string>() { "Some error occurred. Please try again." };
        }
        finally
        {
            AfterAsyncCall(button);

        }
        return resultModel;
    }
    static async Task BackgroundOperation<U>(Task<HttpResponseMessage> operation, ResultViewModel<U> resultModel)
    {
        HttpResponseMessage RawResult = await operation;
        var Response = await RawResult.Content.ReadAsStringAsync();
        resultModel.Status = RawResult.StatusCode;
        if (RawResult.IsSuccessStatusCode)
        {
            var responseObj = await Task.Run(() => JsonConvert.DeserializeObject<U>(Response));
            resultModel.Result = responseObj;
        }
        else
        {
            var responseErrorObj = await Task.Run(() => JsonConvert.DeserializeObject<ErrorModel>(Response));
            resultModel.Errors = new List<string>();
            foreach (var modelState in responseErrorObj.ModelState)
            {
                foreach (var error in modelState.Value)
                {
                    resultModel.Errors.Add(error.ToString());
                }
            }
        }
    }
    static Button BeforeAsyncCall(object sender)
    {
        Button button = null;
        if (sender != null)
            button = (Button)sender;
        if (button != null)
            button.IsEnabled = false;
        UserDialogs.Instance.ShowLoading("Loading", MaskType.Black);
        return button;
    }
    static void AfterAsyncCall(Button button)
    {
        UserDialogs.Instance.HideLoading();
        if (button != null)
            button.IsEnabled = true;
    }
}

Вот вызов моего метода расширения

ResultViewModel<TokenModel> response = await new Service(Settings.BaseUrl).Login(loginModel).ExecuteAsyncOperation<TokenModel>(sender);

ResultViewModel

public class ResultViewModel<T> 
    {
        public HttpStatusCode Status { get; set; }
        public T Result { get; set; }
        public List<string> Errors { get; set; }
    }

Асинхронный метод

public async Task<HttpResponseMessage> Login(LoginViewModel loginModel)
        {
            try
            {

                var dataList = new List<KeyValuePair<string, string>>();
                dataList.Add(new KeyValuePair<string, string>("grant_type", "password"));
                dataList.Add(new KeyValuePair<string, string>("username", loginModel.Email));
                dataList.Add(new KeyValuePair<string, string>("password", loginModel.Password));
                var request = new HttpRequestMessage()
                {
                    RequestUri = new Uri(this.BaseUrl + "token"),
                    Method = HttpMethod.Post,
                    Content = new FormUrlEncodedContent(dataList)
                };
                var authenticateResponse = await Client.SendAsync(request);
                return authenticateResponse;
            }
            catch (Exception ex)
            {
                return null;
            }
        }

Мои вопросы

1)Это хороший подход?

2) Можем ли мы улучшить его с точки зрения производительности?

3) Правильно ли я использую Async?

1 Ответ

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

1) Это хороший подход?

В этом подходе нет ничего плохого.

2) Можем ли мы улучшить его с точки зрения производительности?

Не должно быть никаких проблем с производительностью при использовании метода расширения, но вы можете измерить до 100% определенный.Вы создаете ситуацию упаковки и распаковки с использованием кастинга от object до button.Не могли бы вы просто использовать Button.Используйте ViewElement, если вы хотите поддерживать несколько типов элементов.Кроме того, существуют штрафы за использование async await, но они минимальны и необходимы, чтобы не блокировать пользовательский интерфейс.Вы можете повысить производительность, устранив необходимость повторного создания контекста, добавив .ConfigureAwait(false) к своим задачам, но в вашем случае вам нужен контекст, чтобы снова включить кнопку.Использование dynamic кажется ненужным и имеет некоторые накладные расходы.

3) Правильно ли я использую Async?

Вам не нужно await aTask, если метод просто возвращает Task.Вы можете await это из вызывающего метода.Это уменьшит нагрузку на компилятор и может повысить производительность.Я не проверял это раньше, хотя.

Добавочный номер

public static async Task<ResultViewModel<T>> ExecuteAsyncOperation<T>(this Task<HttpResponseMessage> operation, Button button)
{
    ResultViewModel<T> resultModel = new ResultViewModel<T>();
    try
    {
        if (button != null)
            button.IsEnabled = false;
        HttpResponseMessage RawResult = await operation;
        string Response = await RawResult.Content.ReadAsStringAsync();
        resultModel.Status = RawResult.StatusCode;

        if (RawResult.IsSuccessStatusCode)
        {
            var responseObj = JsonConvert.DeserializeObject<T>(Response);
            resultModel.Result = responseObj;
        }
        else
        {
            //create an error model instead of using dynamic I am guessing modelstate here
            List<ModelState> responseObj = JsonConvert.DeserializeObject<List<ModelState>>(Response);
            resultModel.Errors = new List<string>();
            foreach (ModelState modelState in responseObj)
            {
                foreach (var error in modelState.Errors)
                {
                    resultModel.Errors.Add(error.ToString());
                }
            }
        }
    }
    catch (Exception ex)
    {
        resultModel.Status = HttpStatusCode.InternalServerError;
        resultModel.Errors = new List<string>() { "Some error occurred. Please try again." };
    }
    finally
    {
        if (button != null)
            button.IsEnabled = true;
    }
    return resultModel;
}

Вызов

var button = sender as Button; 
if (button != null)
{
    ResultViewModel<TokenModel> response = await new Service(Settings.BaseUrl).Login(loginModel).ExecuteAsyncOperation<TokenModel>(sender);
}

Запрос

public Task<HttpResponseMessage> Login(LoginViewModel loginModel)
{
    var dataList = new List<KeyValuePair<string, string>>();
    dataList.Add(new KeyValuePair<string, string>("grant_type", "password"));
    dataList.Add(new KeyValuePair<string, string>("username", loginModel.Email));
    dataList.Add(new KeyValuePair<string, string>("password", loginModel.Password));
    var request = new HttpRequestMessage()
    {
        RequestUri = new Uri(this.BaseUrl + "token"),
        Method = HttpMethod.Post,
        Content = new FormUrlEncodedContent(dataList)
    };
    return Client.SendAsync(request);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...