Тип возврата Успех / Неудача для Универсального метода - PullRequest
0 голосов
/ 22 апреля 2019

Я написал общие методы для получения, отправки и размещения.Пример Get Generic Method :

 public async Task<object> GetAsync<T>(string uri, NamingStrategy namingStrategy)
    {
        using (var requestMessage = new HttpRequestMessage(HttpMethod.Get, uri))
        {
            return await ProcessAsync<T>(requestMessage, namingStrategy);
        }
    }

и ProcessAync :

public async Task<object> ProcessAsync<T>(HttpRequestMessage request, NamingStrategy namingStrategy)
    {
        if (!string.IsNullOrEmpty(AuthToken))
        {
            request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", AuthToken);
        }
        HttpResponseMessage response = await _client.SendAsync(request);
        if (response.IsSuccessStatusCode)
        {
            _logger.LogInformation("Request Succeeded");
            var dezerializerSettings = new JsonSerializerSettings
            {
                ContractResolver = new DefaultContractResolver
                {
                    NamingStrategy = namingStrategy
                }
            };
            T responseModel = JsonConvert.DeserializeObject<T>(await response.Content.ReadAsStringAsync(), dezerializerSettings);
            return responseModel;
        }
        else
        {
            return await GetFailureResponseModel(response);

        }
    }

, чем я вызываю этот метод get, какчто в моем SingletonClass

 public async Task<object> GetShops(string category)
    {
        _logger.LogInformation("ClubMatas outgoing request: {RequestName}", nameof(GetShops));
        return await _client.GetAsync<ShopsResponseModel>($"v2/shops?category={WebUtility.UrlEncode(category)}");
    }

И этот метод вызывается в моем контроллере следующим образом

 public async Task<ActionResult<object>> GetShops([FromQuery(Name = "category")]string category)
    {
        var response = await _httpClient.GetShops(category);
        return ParseResponse<ShopsResponseModel>(response);
    }

и ParseResponse равно

 protected ActionResult<object> ParseResponse<T>(object response)
    {
        if (response.GetType() == typeof(T))
        {
            return Ok(response);
        }
        else
        {
            return Error(response);
        }
    }

Как показывает цепочка вызовов, я ожидаю, что в моем Api-ответе будут другие SuccessModel или FailureModel, и в связи с этим я должен использовать object в качестве возвращаемого типа.Но у меня есть чувство, что я не должен использовать тип object для возврата.К вашему сведению выше цепочка работает отлично.Я просто ищу больше рефакторинга или улучшения моего текущего потока.ищу более элегантное решение этой проблемы.Пожалуйста, предложите любое другое решение для моей проблемы.

Обновление Я попытался @ChrisPratt предложить использовать интерфейс, но это решение не работает, или, возможно, я делаю это неправильно.Итак, я создал этот пустой интерфейс

public interface IResult
{
}

И я расширил и мой ShopResponseModel и FailureResponseModel из IResult интерфейса, и обновил методы, подобные этому.

 public async Task<IResult> GetShops(string category)
    {
        _logger.LogInformation("ClubMatas outgoing request: {RequestName}", nameof(GetShops));
        return await _client.GetAsync<IResult>($"v2/shops?category={WebUtility.UrlEncode(category)}");
    }

и

 public async Task<T> GetAsync<T>(string uri, NamingStrategy namingStrategy)
    {
        using (var requestMessage = new HttpRequestMessage(HttpMethod.Get, uri))
        {
            return await ProcessAsync<T>(requestMessage, namingStrategy);
        }
    }

и я обновил ProcessAsync тип возврата с объект до T .Но получаю ошибки.

1 Ответ

0 голосов
/ 22 апреля 2019

Но я чувствую, что не должен использовать тип объекта для возврата.

Да. Не используйте object для возвращаемых значений. Это практически бесполезно в качестве возвращаемого типа. Что вы должны сделать, это вернуть интерфейс. Например, вы можете сделать что-то вроде:

public interface IResponseStatusModel
{
    bool Succeeded { get; }
    int StatusCode { get; }
    // etc.
}

Тогда:

public class SuccessModel : IResponseStatusModel

public class FailureModel : IResponseStatusModel

Затем вы можете вернуть IResponseStatusModel, и, основываясь на интерфейсе, вы сможете взаимодействовать с любым свойством или методом, определенным в интерфейсе, независимо от того, какую модель вы на самом деле возвращаете.

Однако у вас не должно быть отдельных классов для успеха / неудачи. Создание интерфейса, который может вообще позволить вам взаимодействовать с любым из них, в любом случае приведет к размытию границ между ними. Вместо этого вы должны просто вернуть один тип модели, который имеет свойства, подобные описанным выше, и, возможно, свойство списка для ошибок и тому подобное. Например:

public class ProcessResult
{
    public ProcessResult(int statusCode) : this(statusCode, null) {}

    public ProcessResult(int statusCode, IEnumerable<string> errors)
    {
        Succeeded = statusCode < 300;
        StatusCode = statusCode;
        Errors = errors;
    }

    public bool Succeeded { get; private set; }
    public int StatusCode { get; private set; }
    public IEnumerable<string> Errors { get; private set; }
}

Это очень базовый пример. Возможно, вы захотите создать его побольше и предоставить более надежное решение для определения, успешно ли выполнена задача. Общая идея заключается в том, что вы предоставляете как можно больше соответствующей информации о результате операции. Затем в своем коде вы можете просто перейти на Succeeded и затем соответствующим образом обработать ситуацию:

if (result.Succeeded)
{
    // do something on success
}
else
{
    // do something on failure
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...