通用方法的成功/失败返回类型

时间:2019-04-22 11:22:46

标签: c# generics asp.net-core

我已经为Get,Post和Put编写了通用方法。 获取通用方法的示例是:

 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);

        }
    }

比我在SingletonClass中调用此get方法

 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接口扩展了FailureResponseModelIResult,并更新了类似的方法。

 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的返回类型从 object 更新为 T 。但是会出错。

1 个答案:

答案 0 :(得分:0)

  

但是我觉得我不应该使用对象类型来返回。

是的。不要使用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
}