在.NET Core中将HttpResponseMessage转换为IActionResult

28

我正在将一些先前使用 .NET Framework 编写的代码移植到 .NET Core。

我之前有这样的代码:

HttpResponseMessage result = await client.SendAync(request);
if (result.StatusCode != HttpStatusCode.OK)
{
    IHttpActionResult response = ResponseMessage(result);
    return response;
}

此函数的返回值现在为IActionResult

我如何从HttpResponseMessage result对象获取IActionResult并返回它?


你正在运行.NET Core 2.1吗? - DavidG
不知道 ResponseMessage 的作用,我们怎么能帮助您呢? - Federico Dipuma
2
@FedericoDipuma中的ResponseMessage是来自Asp.Net Web API 2 ApiControllerHttpResponseMessage转换为IHttpActionResult的。OP正在将之前的代码移植到当前版本。 - Nkosi
@FedericoDipuma ResponseMessageSystem.Web.Http 库中的一个函数部分。它只是根据您指定的 HttpResponseMessage 创建一个 ResponseMessageResult - Lyco
完全忘记了那个方法。谢谢您的澄清@Nkosi - Federico Dipuma
看起来似乎没有内置的方法可以完成您所请求的操作。您可以始终构建自己的扩展方法来提取必要的数据并返回适当的响应。 - Nkosi
6个回答

17

你可以使用硬编码状态代码返回,例如Ok();BadRequest();

或者使用动态状态代码返回

StatusCode(<Your status code number>,<Optional return object>);

这是使用 Microsoft.AspNetCore.Mvc。

以下是更详细说明的 this.StatusCode:

/* "this" comes from your class being a subclass of Microsoft.AspNetCore.Mvc.ControllerBase */
StatusCodeResult scr = this.StatusCode(200);
/* OR */
Object myObject = new Object();
ObjectResult ores = this.StatusCode(200, myObject);
return scr; /* or return ores;*/

你能添加完全限定名称吗?或者加上“using”语句?谢谢。 - granadaCoder
@granadaCoder sure - Lyco

16

通过使用Microsoft.AspNetCore.Mvc.WebApiCompatShim nuget包,您应该能够将现有的代码迁移到ASP.NET Core 2.x。

然后,您可以执行以下操作之一:

1 使用ResponseMessageResult

return new ResponseMessageResult(result);

继承您的Controller类自ApiController,并保留您的代码不变:

public class MyController : ApiController 
{
    public IActionResult Get()
    {
        // other code...
        HttpResponseMessage result = await client.SendAync(request);
        if (result.StatusCode != HttpStatusCode.OK)
        {
            IActionResult response = ResponseMessage(result);
            return response;
        }
        // other code...
    }    
}

官方文档中有更多信息。


在 .Net Core 中是否有 ApiController?我认为在 .Net Core 中只有一个 Controller 基类,是这样吗? - LP13
@LP13 如答案所述,ApiController 是使用 Microsoft.AspNetCore.Mvc.WebApiCompatShim nuget 包时获得的兼容性类。 - Federico Dipuma
7
这个回复中缺少的是,你需要在服务器Startup类的ConfigureServices函数中调用services.AddMvc().AddWebApiConventions();来启用WebApi兼容层。(否则,服务器将仅尝试将ResponseMessage对象序列化为JSON。) - Mike Rosoft
Razor页面能够实现这个吗? - Mohamad Elnaqeeb
“_as stated in the answer_” - 不过,您的答案表明:“使用WebApiCompatShim来执行X,或者作为替代方案,使用ApiController来执行Y”,这意味着在ApiController中不需要WebApiCompatShim。如果情况并非如此,您可能需要重新措辞。 - RyanfaeScotland

6

在.NET v5 (之前称为.NET Core v5)中,这变得更加容易实现。在Microsoft.AspNetCore.Mvc.Core DLL中可以找到ControllerBase类,其中包含许多返回从IActionResult继承的对象的方法。 IActionResultHttpResponseMessage的替代品。以下是我移植的一个基于.NET Framework v4.6的Web API方法,它用于返回文件。

[HttpGet]
public IHttpActionResult GetFooBar()
{
    var fileContentByteArray = foodBarDomainService.GetExeByteArray();
    var result = new HttpResponseMessage(HttpStatusCode.OK)
    {
        Content = new ByteArrayContent(fileContentByteArray)
    };
    result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
    {
        FileName = "FooBar.exe"
    };
    result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
    return ResponseMessage(result);
}

这是我将其移植到.NET v5的代码:

[HttpGet("GetFooBar", Name = "GetFooBar")]
public IActionResult GetFooBar(string token)
{
    var fileContentByteArray = foodBarDomainService.GetExeByteArray();
    return File(fileContentByteArray, "application/octet-stream", "FooBar.exe");
}

以下是返回实现了IActionResult接口的类以服务于特定目的的所有方法的完整列表:
public virtual AcceptedResult Accepted(Uri uri, [ActionResultObjectValue] object value);
public virtual AcceptedResult Accepted(string uri, [ActionResultObjectValue] object value);
public virtual AcceptedResult Accepted(Uri uri);
public virtual AcceptedResult Accepted([ActionResultObjectValue] object value);
public virtual AcceptedResult Accepted();
public virtual AcceptedResult Accepted(string uri);
public virtual AcceptedAtActionResult AcceptedAtAction(string actionName, string controllerName, object routeValues, [ActionResultObjectValue] object value);
public virtual AcceptedAtActionResult AcceptedAtAction(string actionName, object routeValues, [ActionResultObjectValue] object value);
public virtual AcceptedAtActionResult AcceptedAtAction(string actionName);
public virtual AcceptedAtActionResult AcceptedAtAction(string actionName, string controllerName);
public virtual AcceptedAtActionResult AcceptedAtAction(string actionName, [ActionResultObjectValue] object value);
public virtual AcceptedAtActionResult AcceptedAtAction(string actionName, string controllerName, [ActionResultObjectValue] object routeValues);
public virtual AcceptedAtRouteResult AcceptedAtRoute(string routeName);
public virtual AcceptedAtRouteResult AcceptedAtRoute(object routeValues, [ActionResultObjectValue] object value);
public virtual AcceptedAtRouteResult AcceptedAtRoute(string routeName, object routeValues, [ActionResultObjectValue] object value);
public virtual AcceptedAtRouteResult AcceptedAtRoute(string routeName, object routeValues);
public virtual AcceptedAtRouteResult AcceptedAtRoute([ActionResultObjectValue] object routeValues);
public virtual BadRequestResult BadRequest();
public virtual BadRequestObjectResult BadRequest([ActionResultObjectValue] object error);
public virtual BadRequestObjectResult BadRequest([ActionResultObjectValue] ModelStateDictionary modelState);
public virtual ChallengeResult Challenge(params string[] authenticationSchemes);
public virtual ChallengeResult Challenge();
public virtual ChallengeResult Challenge(AuthenticationProperties properties);
public virtual ChallengeResult Challenge(AuthenticationProperties properties, params string[] authenticationSchemes);
public virtual ConflictResult Conflict();
public virtual ConflictObjectResult Conflict([ActionResultObjectValue] object error);
public virtual ConflictObjectResult Conflict([ActionResultObjectValue] ModelStateDictionary modelState);
public virtual ContentResult Content(string content);
public virtual ContentResult Content(string content, MediaTypeHeaderValue contentType);
public virtual ContentResult Content(string content, string contentType, Encoding contentEncoding);
public virtual ContentResult Content(string content, string contentType);
public virtual CreatedResult Created(Uri uri, [ActionResultObjectValue] object value);
public virtual CreatedResult Created(string uri, [ActionResultObjectValue] object value);
public virtual CreatedAtActionResult CreatedAtAction(string actionName, string controllerName, object routeValues, [ActionResultObjectValue] object value);
public virtual CreatedAtActionResult CreatedAtAction(string actionName, object routeValues, [ActionResultObjectValue] object value);
public virtual CreatedAtActionResult CreatedAtAction(string actionName, [ActionResultObjectValue] object value);
public virtual CreatedAtRouteResult CreatedAtRoute(object routeValues, [ActionResultObjectValue] object value);
public virtual CreatedAtRouteResult CreatedAtRoute(string routeName, object routeValues, [ActionResultObjectValue] object value);
public virtual CreatedAtRouteResult CreatedAtRoute(string routeName, [ActionResultObjectValue] object value);
public virtual FileStreamResult File(Stream fileStream, string contentType, string fileDownloadName);
public virtual VirtualFileResult File(string virtualPath, string contentType, string fileDownloadName, DateTimeOffset? lastModified, EntityTagHeaderValue entityTag, bool enableRangeProcessing);
public virtual VirtualFileResult File(string virtualPath, string contentType, string fileDownloadName, DateTimeOffset? lastModified, EntityTagHeaderValue entityTag);
public virtual VirtualFileResult File(string virtualPath, string contentType, DateTimeOffset? lastModified, EntityTagHeaderValue entityTag, bool enableRangeProcessing);
public virtual VirtualFileResult File(string virtualPath, string contentType, DateTimeOffset? lastModified, EntityTagHeaderValue entityTag);
public virtual VirtualFileResult File(string virtualPath, string contentType, string fileDownloadName, bool enableRangeProcessing);
public virtual VirtualFileResult File(string virtualPath, string contentType, string fileDownloadName);
public virtual VirtualFileResult File(string virtualPath, string contentType, bool enableRangeProcessing);
public virtual VirtualFileResult File(string virtualPath, string contentType);
public virtual FileStreamResult File(Stream fileStream, string contentType, string fileDownloadName, DateTimeOffset? lastModified, EntityTagHeaderValue entityTag, bool enableRangeProcessing);
public virtual FileStreamResult File(Stream fileStream, string contentType, string fileDownloadName, DateTimeOffset? lastModified, EntityTagHeaderValue entityTag);
public virtual FileStreamResult File(Stream fileStream, string contentType, DateTimeOffset? lastModified, EntityTagHeaderValue entityTag, bool enableRangeProcessing);
public virtual FileStreamResult File(Stream fileStream, string contentType, DateTimeOffset? lastModified, EntityTagHeaderValue entityTag);
public virtual FileStreamResult File(Stream fileStream, string contentType, string fileDownloadName, bool enableRangeProcessing);
public virtual FileStreamResult File(Stream fileStream, string contentType);
public virtual FileContentResult File(byte[] fileContents, string contentType, string fileDownloadName, DateTimeOffset? lastModified, EntityTagHeaderValue entityTag, bool enableRangeProcessing);
public virtual FileContentResult File(byte[] fileContents, string contentType, string fileDownloadName, DateTimeOffset? lastModified, EntityTagHeaderValue entityTag);
public virtual FileContentResult File(byte[] fileContents, string contentType, DateTimeOffset? lastModified, EntityTagHeaderValue entityTag, bool enableRangeProcessing);
public virtual FileContentResult File(byte[] fileContents, string contentType, DateTimeOffset? lastModified, EntityTagHeaderValue entityTag);
public virtual FileContentResult File(byte[] fileContents, string contentType, string fileDownloadName, bool enableRangeProcessing);
public virtual FileContentResult File(byte[] fileContents, string contentType, string fileDownloadName);
public virtual FileContentResult File(byte[] fileContents, string contentType, bool enableRangeProcessing);
public virtual FileContentResult File(byte[] fileContents, string contentType);
public virtual FileStreamResult File(Stream fileStream, string contentType, bool enableRangeProcessing);
public virtual ForbidResult Forbid(params string[] authenticationSchemes);
public virtual ForbidResult Forbid();
public virtual ForbidResult Forbid(AuthenticationProperties properties, params string[] authenticationSchemes);
public virtual ForbidResult Forbid(AuthenticationProperties properties);
public virtual LocalRedirectResult LocalRedirect(string localUrl);
public virtual LocalRedirectResult LocalRedirectPermanent(string localUrl);
public virtual LocalRedirectResult LocalRedirectPermanentPreserveMethod(string localUrl);
public virtual LocalRedirectResult LocalRedirectPreserveMethod(string localUrl);
public virtual NoContentResult NoContent();
public virtual NotFoundObjectResult NotFound([ActionResultObjectValue] object value);
public virtual NotFoundResult NotFound();
public virtual OkResult Ok();
public virtual OkObjectResult Ok([ActionResultObjectValue] object value);
public virtual PhysicalFileResult PhysicalFile(string physicalPath, string contentType, DateTimeOffset? lastModified, EntityTagHeaderValue entityTag);
public virtual PhysicalFileResult PhysicalFile(string physicalPath, string contentType, string fileDownloadName, DateTimeOffset? lastModified, EntityTagHeaderValue entityTag, bool enableRangeProcessing);
public virtual PhysicalFileResult PhysicalFile(string physicalPath, string contentType, string fileDownloadName, DateTimeOffset? lastModified, EntityTagHeaderValue entityTag);
public virtual PhysicalFileResult PhysicalFile(string physicalPath, string contentType, DateTimeOffset? lastModified, EntityTagHeaderValue entityTag, bool enableRangeProcessing);
public virtual PhysicalFileResult PhysicalFile(string physicalPath, string contentType, string fileDownloadName, bool enableRangeProcessing);
public virtual PhysicalFileResult PhysicalFile(string physicalPath, string contentType, string fileDownloadName);
public virtual PhysicalFileResult PhysicalFile(string physicalPath, string contentType, bool enableRangeProcessing);
public virtual PhysicalFileResult PhysicalFile(string physicalPath, string contentType);
public virtual ObjectResult Problem(string detail = null, string instance = null, int? statusCode = null, string title = null, string type = null);
public virtual RedirectResult Redirect(string url);
public virtual RedirectResult RedirectPermanent(string url);
public virtual RedirectResult RedirectPermanentPreserveMethod(string url);
public virtual RedirectResult RedirectPreserveMethod(string url);
public virtual RedirectToActionResult RedirectToAction(string actionName, string controllerName, string fragment);
public virtual RedirectToActionResult RedirectToAction(string actionName, string controllerName, object routeValues);
public virtual RedirectToActionResult RedirectToAction(string actionName, string controllerName, object routeValues, string fragment);
public virtual RedirectToActionResult RedirectToAction(string actionName);
public virtual RedirectToActionResult RedirectToAction(string actionName, object routeValues);
public virtual RedirectToActionResult RedirectToAction();
public virtual RedirectToActionResult RedirectToAction(string actionName, string controllerName);
public virtual RedirectToActionResult RedirectToActionPermanent(string actionName, string controllerName, object routeValues, string fragment);
public virtual RedirectToActionResult RedirectToActionPermanent(string actionName, string controllerName, object routeValues);
public virtual RedirectToActionResult RedirectToActionPermanent(string actionName, string controllerName, string fragment);
public virtual RedirectToActionResult RedirectToActionPermanent(string actionName, string controllerName);
public virtual RedirectToActionResult RedirectToActionPermanent(string actionName, object routeValues);
public virtual RedirectToActionResult RedirectToActionPermanent(string actionName);
public virtual RedirectToActionResult RedirectToActionPermanentPreserveMethod(string actionName = null, string controllerName = null, object routeValues = null, string fragment = null);
public virtual RedirectToActionResult RedirectToActionPreserveMethod(string actionName = null, string controllerName = null, object routeValues = null, string fragment = null);
public virtual RedirectToPageResult RedirectToPage(string pageName);
public virtual RedirectToPageResult RedirectToPage(string pageName, string pageHandler, object routeValues, string fragment);
public virtual RedirectToPageResult RedirectToPage(string pageName, string pageHandler, string fragment);
public virtual RedirectToPageResult RedirectToPage(string pageName, string pageHandler, object routeValues);
public virtual RedirectToPageResult RedirectToPage(string pageName, string pageHandler);
public virtual RedirectToPageResult RedirectToPage(string pageName, object routeValues);
public virtual RedirectToPageResult RedirectToPagePermanent(string pageName, string pageHandler, string fragment);
public virtual RedirectToPageResult RedirectToPagePermanent(string pageName);
public virtual RedirectToPageResult RedirectToPagePermanent(string pageName, object routeValues);
public virtual RedirectToPageResult RedirectToPagePermanent(string pageName, string pageHandler);
public virtual RedirectToPageResult RedirectToPagePermanent(string pageName, string pageHandler, object routeValues, string fragment);
public virtual RedirectToPageResult RedirectToPagePermanentPreserveMethod(string pageName, string pageHandler = null, object routeValues = null, string fragment = null);
public virtual RedirectToPageResult RedirectToPagePreserveMethod(string pageName, string pageHandler = null, object routeValues = null, string fragment = null);
public virtual RedirectToRouteResult RedirectToRoute(string routeName);
public virtual RedirectToRouteResult RedirectToRoute(string routeName, object routeValues);
public virtual RedirectToRouteResult RedirectToRoute(string routeName, string fragment);
public virtual RedirectToRouteResult RedirectToRoute(string routeName, object routeValues, string fragment);
public virtual RedirectToRouteResult RedirectToRoute(object routeValues);
public virtual RedirectToRouteResult RedirectToRoutePermanent(string routeName, string fragment);
public virtual RedirectToRouteResult RedirectToRoutePermanent(string routeName, object routeValues);
public virtual RedirectToRouteResult RedirectToRoutePermanent(string routeName, object routeValues, string fragment);
public virtual RedirectToRouteResult RedirectToRoutePermanent(string routeName);
public virtual RedirectToRouteResult RedirectToRoutePermanent(object routeValues);
public virtual RedirectToRouteResult RedirectToRoutePermanentPreserveMethod(string routeName = null, object routeValues = null, string fragment = null);
public virtual RedirectToRouteResult RedirectToRoutePreserveMethod(string routeName = null, object routeValues = null, string fragment = null);
public virtual SignInResult SignIn(ClaimsPrincipal principal, string authenticationScheme);
public virtual SignInResult SignIn(ClaimsPrincipal principal, AuthenticationProperties properties);
public virtual SignInResult SignIn(ClaimsPrincipal principal, AuthenticationProperties properties, string authenticationScheme);
public virtual SignInResult SignIn(ClaimsPrincipal principal);
public virtual SignOutResult SignOut();
public virtual SignOutResult SignOut(AuthenticationProperties properties);
public virtual SignOutResult SignOut(params string[] authenticationSchemes);
public virtual SignOutResult SignOut(AuthenticationProperties properties, params string[] authenticationSchemes);
public virtual StatusCodeResult StatusCode([ActionResultStatusCode] int statusCode);

4

我曾经遇到过将代码移植到 .net6 的类似问题,其中控制器不再使用 HttpResponseMessage。无论如何,这些对象都会被返回为普通对象。即使您使用 500 状态代码返回 HttpResponseMessage,您也会得到将所有内容包装在 200 响应代码结果中的结果。因此,我最终编写了以下扩展方法:

public static async Task<ContentResult> ToContentResultAsync(this 
HttpResponseMessage responseMessage, string contentType)
        {
            var contentRes = new ContentResult();
            contentRes.StatusCode = (int)responseMessage.StatusCode;
            contentRes.Content = await responseMessage.Content.ReadAsStringAsync();
            contentRes.ContentType = contentType;
            return contentRes;
        }

并在控制器操作中使用它,例如:

[HttpPut, Route("some-route")]       
public async Task<IActionResult> SomeAction(...)
{
    var someClient = new HttpClient();           
        
    var res = await client.PutAsync($"api/urlHere");  

    // ... more stuff happening here       
                 
    return await res.ToContentResultAsync("application/json");           
      
}

上述方法是针对application/json内容设计的,但您可以根据自己的需要调整它以适用于任何内容和对象类型。

希望这能帮助那些处理.net core.net6迁移的人。


3

感谢大家的回答。我选择了稍微不同的方法。我猜这段代码的意图是,如果SendAsync出现任何错误,我想返回该错误消息。因此,我将其更改为类似以下内容:

if (result.StatusCode != HttpStatusCode.OK)
{
    return BadRequest(result.ReasonPhrase);
}

2
你应该编写一个错误处理中间件,它可以自动为你完成。 - PmanAce

3

这对我有效。 .NET Core 6.0

public async Task<IActionResult> GetAll(string catalogname,[FromQuery] GetAllQuery query)
    {
        String hardCodedJson = "{\"Id\":\"123\",\"DateOfRegistration\":\"2012-10-21T00:00:00+05:30\",\"Status\":0}";

        return Content(hardCodedJson , "application/json");
    }

2
目前你的回答不够清晰。请编辑并添加更多细节,以帮助其他人理解它如何回答所提出的问题。你可以在帮助中心找到有关如何撰写好答案的更多信息。 - Community
谢谢!太简单了。我给你点赞了。这里发布的东西从来都不容易或简单。你的解决方案是新的.NET CORE方式。所以当然非常好用。平安。 - Stokely
如果这能帮助其他人,他的解决方案就比其他所有解决方案都优秀!它展示了ASP.NET Core中典型的IActionResult。IActionResult返回类型允许您返回任何类型的数据。在这种情况下,他有一个“JSON字符串”,该字符串使用转义或斜杠进行格式化,这在ASP.NET中很典型。 "return Content()"或ContentResult是一种ActionResult类型,它允许您返回包括此字符串的响应到浏览器,但具有“application/json”的HttpHeader内容类型(或MIME类型)。这告诉浏览器将其接受为JSON。 JSON是任何有效的JSON字符串,甚至包括字符串格式。 - Stokely

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接