【问题标题】:How to return Generic response from Controller?如何从控制器返回通用响应?
【发布时间】:2021-03-24 14:01:15
【问题描述】:

Net core 应用程序和调用其他 .Net Core Web API 应用程序。我正在调用控制器方法如下

public async Task<T> SendRequest<T, U>(U request, string methodName, HttpMethod reqtype, string token)
        {
            T res = default(T);
            try
            {
                string url = methodName;
                string contentJson = JsonConvert.SerializeObject(request);
                var content = new StringContent(contentJson, Encoding.UTF8, "application/json");
                var actualRequest = new HttpRequestMessage(reqtype, url);
                actualRequest.Content = content;
                _httpClient.DefaultRequestHeaders.Clear();
                _httpClient.DefaultRequestHeaders.Add("Authorization", token);
                var rawData = await _httpClient.SendAsync(actualRequest);
                var processedData = await rawData.Content.ReadAsStringAsync().ConfigureAwait(false);
                res = JsonConvert.DeserializeObject<T>(processedData);
            }
            catch (Exception ex)
            {
                _reqHandler.RaiseBusinessException(MethodBase.GetCurrentMethod()?.DeclaringType?.DeclaringType?.Name
                    , MethodBase.GetCurrentMethod().Name,
                    "InputType: " + typeof(U) + " || OutputType: " + typeof(T) + " || Error Message: " + ex.Message);
            }
            return res;
        }  

以下是从 API 控制器返回的示例

return StatusCode(404, result.MapFileFileUploadSummary);
 return StatusCode((int)System.Net.HttpStatusCode.Unauthorized);

在上面的代码中,当我返回一些状态码时,我想将它绑定到通用类型 T。例如我正在调用一个方法

 _Client.SendRequest<ObjectResult, requestModel>()

我发送 ObjectResult 类型作为返回类型。例如,我在处理数据中得到以下响应,

"{\"type\":\"https://tools.ietf.org/html/rfc7235#section-3.1\",\"title\":\"Unauthorized\",\"status\":401,\"traceId\":\"00-e517f28f9c0b0441a8634c1c703a1cae-f64589d11056ad45-00\"}"

但无法绑定到

res = JsonConvert.DeserializeObject&lt;T&gt;(processedData); 这没有返回任何内容我在这里添加屏幕截图

这里 T 是 ObjectResult 类型。我在这里寻找通用响应类型,以便我可以始终将它绑定到类型 T。有人可以帮助我实现这个实现。任何帮助,将不胜感激。谢谢

【问题讨论】:

  • “无法绑定”是什么意思?代码应该根据我编译。还是运行时问题?
  • 嗨 Arcord 我已经更新了我的问题。我要绑定 "{\"type\":\"tools.ietf.org/html/rfc7235#section-3.1\",\"title\":\"Unauthorized\",\"status\":401,\"traceId\":\"00- e517f28f9c0b0441a8634c1c703a1cae-f64589d11056ad45-00\"}" 到 JsonConvert.DeserializeObject(processedData) 但我在上面添加了屏幕截图,状态代码为 null 我期待未经授权
  • 如果我理解正确,我永远不会工作。例如,在您的对象 ObjectResult 中,状态代码的字段被命名为“StatusCode”,但在您的 JSON 中,它被命名为“status”(或“title”,取决于您是否需要代码或名称)。您应该创建一个与您的 JSON 对应的类,将 JSON 反序列化为该类型并映射到您的“ObjectResult”。
  • 我知道我可以创建具有属性类型、标题、状态的自定义类,我可以发送“没关系”。它可能不会总是返回相同的响应。根据上面的示例,它会返回 Unauthorized 但在某些情况下它可能会返回实际数据,对吗?它返回什么数据取决于我的 API。所以我正在寻找某种方式来处理我想要处理的任何数据。有什么办法可以更好的处理?
  • 好的,现在你的问题对我来说更清楚了......我会尝试制定一个答案:-)

标签: c# .net asp.net-core asp.net-core-mvc actionresult


【解决方案1】:

您遇到的问题是:如果发生错误,JSON 将与成功时完全不同。

为了举例,我将隐藏有关 HTTP 请求的大部分内容:

public async Task<ActionResult<T>> SendRequest<T, U>(U request, string methodName, HttpMethod reqtype, string token);

对我来说,你不应该返回“T”,而应该返回“ActionResult”。您的代码仍然不知道实际内容 (T) 是什么,但知道它将返回 ActionResult。它会减轻其余部分的负担。

var response = await _httpClient.SendAsync(actualRequest);
if (!response.IsSuccessStatusCode) 
{
   return new StatusCodeResult((int)response.StatusCode)
}
var responseData = JsonConvert.DeserializeObject<T>(await rawData.Content.ReadAsStringAsync());
return new ObjectResult(responseData);

在所有情况下,您都会有一个可以直接从控制器返回的 ActionResult。

如果发生错误,结果只会是其他服务器返回的状态码。

如果成功,您将让另一台服务器发送数据。

我认为万一出错,将状态码返回给您的用户就足够了,但如果要发送整个对象,您也可以这样做。您只需要首先创建一个类,该类将代表发生错误时发送的数据:

var response = await _httpClient.SendAsync(actualRequest);

object responseData;

if (response.IsSuccessStatusCode) 
{
    responseData = JsonConvert.DeserializeObject<T>(await rawData.Content.ReadAsStringAsync());
}
else 
{
   responseData = JsonConvert.DeserializeObject<YourClassInCaseOfError>(await rawData.Content.ReadAsStringAsync());
}

return new ObjectResult(responseData) 
{
   StatusCode = (int)response.StatusCode,  
}

您还必须将方法签名更改为:

public async Task<ActionResult> SendRequest<T, U>(U request, string methodName, HttpMethod reqtype, string token);

由于第二个示例可能会返回 2 种不同的类型(数据类型或错误类型),因此您必须使用 ActionResult,而不是 ActionResult

【讨论】:

  • 嗨,Arcord。感谢您的理解和提供答案。我只是停留在最后一步。 StatusCodeResult(responseData) StatusCodeResult 将接受 int 作为参数,但我们正在传递导致错误的 responseData。知道我们如何解决这个问题
  • 似乎我有点太快了,所以我用接受数据和状态代码的 ObjectResult 替换了 StatusCodeResult。如果您使用的是第二种解决方案,则方法签名应该略有不同,我也将新版本放入响应中:-)
  • 嗨 Arcord 我将方法签名更改为公共异步 Task SendRequest(U request, string methodName, HttpMethod reqtype, string token) 但这条线不再起作用 responseData = JsonConvert.DeserializeObject(等待响应.Content.ReadAsStringAsync());因为我没有正确的 T。我说的对吗
  • 完全正确,我解决了这个问题。我从 ActionResult 中删除了 T ,因为它不再需要,但仍然需要在签名中包含它! :-)
  • 一切正常。我正在返回例如 return StatusCode(200, result.MapFileFileUploadSummary);在调用方法中,我有类似 var result = await _geoClient.SendRequestMapFileUpload( new MapFileRequestModel { MapFileDetailsEntity = mapFileDetailsEntity, SiteAssessmentRequestId = SiteAssessmentRequestId }, "CheckDuplicateMapFiles", HttpMethod.Post).ConfigureAwait(false);返回确定(结果);
猜你喜欢
  • 2013-09-20
  • 1970-01-01
  • 2014-12-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-30
  • 2017-01-28
  • 1970-01-01
相关资源
最近更新 更多