【问题标题】:HTTPClient error when calling ASP.NET Web API REST service from ASP.NET MVC app从 ASP.NET MVC 应用程序调用 ASP.NET Web API REST 服务时出现 HTTPClient 错误
【发布时间】:2020-12-07 09:54:22
【问题描述】:

我有一个调用 ASP.NET Web Api REST 服务的 ASP.NET MVC 应用程序:

public class MyClass
{
    private static HttpClient client = new HttpClient();

    public async Task DumpWarehouseDataIntoFile(Warehouse myData, string path, string filename)  // See Warehouse class later in this post
    { 
        try
        {

           //Hosted web API REST Service base url  
           string Baseurl = "http://XXX.XXX.XX.X:YYYY/";  

           //using (var client = new HttpClient())  --> I have declared client as an static variable
           //{  
            //Passing service base url  
            client.BaseAddress = new Uri(Baseurl);  

            client.DefaultRequestHeaders.Clear();  
            //Define request data format  
            client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));  
              
            // Serialize parameter to pass to the asp web api rest service
            string jsonParam = Newtonsoft.JsonConvert.SerializeObject(myData);

            //Sending request to find web api REST service resource  using HttpClient

            var httpContent = new StringContent(jsonParam, Encoding.UTF8, "application/json");

            HttpResponseMessage Res = await client.PostAsync("api/Warehouse/DumpIntoFile", httpContent);  

            //Checking the response is successful or not which is sent using HttpClient  
            if (Res.IsSuccessStatusCode)  
            {  
               // Some other sftuff here
            }
           //}
         }
         catch (Exception ex)
         {
              // Do some stuff here
         } // End Try

    } // End DumpWarehouseDataIntoFile method
} // End class

ASP.NET Web API REST 控制器:

public class WarehouseController : ApiController
{ 
    public bool DumpIntoFile(string data)
    {
           // Stuff here
    }
}

我使用了一个 HttpClient 静态变量,我没有将它包含在“使用”块中,因为不推荐使用它,如以下链接所述:YOU'RE USING HTTPCLIENT WRONG AND IT IS DESTABILIZING YOUR SOFTWARE

执行此代码时失败并出现错误:

System.Net.Http.HttpRequestException:发送时出错 请求。 System.Net.WebException:远程名称不能是 已解决:'xxx'

我想我不需要处理 HttpClient 客户端对象,对吧?

我该如何解决这个问题?

我正在使用 Visual Studio 2013 和 NET 4.5(非核心)

2020 年 12 月 10 日更新: 由于内部 DNS 中未正确配置 ASP.NET Web API REST Url,因此发生了上一个错误。

现在在解决之前的错误后,我得到以下错误:

404 未找到

下面是client.PostAsync返回的一些错误消息:

Ping 到 ASP.NET Web API Rest 工作正常。

也许它在下面的 App_Start\WebApiConfig.cs 下我的 web api 路由配置中缺少一些东西?

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        // Configuración y servicios de API web

        // Rutas de API web
        config.MapHttpAttributeRoutes();

        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );
    }
}

【问题讨论】:

  • “无法解析远程名称”听起来更像是无法访问 API。你能 Ping 服务器还是通过 cUrl / Postman 试试?
  • 我同意 Fildor 关于例外的看法。验证远程 API 是否可访问,并仔细检查您的请求以确保地址正确。另外,我建议您看看使用 HttpClient Factory 来创建您的 HttpClient 对象。文档链接:docs.microsoft.com/en-us/aspnet/core/fundamentals/…
  • 你应该使用 HttpClientFactory。 HttpClient 缓存套接字连接,因此如果 DNS 条目发生更改,它将继续尝试连接到错误的服务器。 DNS 解析最多可能需要 15 秒,因此这是一个巨大的增益。 HttpClientFactory 会定期(默认每 10 分钟)回收连接,因此它最终会在不失去缓存优势的情况下获取任何 DNS 更改。
  • 尝试将 DumpWarehouseDataIntoFile() 返回类型更改为 Task 并等待它完成?
  • @jandrew HttpClient Factory 是否可用于标准 ASP.NET(非核心)?您能否发布一些关于如何调整我的小代码以应用 HttpClient Factory 的小代码 sn-p?任何代码 sn-p 将不胜感激。我从未使用过 HttpClient Factory,我认为使用它是一个好习惯。因此,如果您提供一些关于如何使我的代码适应它的小代码,我将非常感谢您。提前致谢。

标签: c# asp.net-mvc asp.net-web-api asp.net-web-api2 dotnet-httpclient


【解决方案1】:

我假设您正在使用基于您提供的 WebApiConfig 的 Web API 2。关于您收到的 404 响应,这完全源于您的控制器操作中对路由的错误使用或缺少路由。

使用您的示例 WebApiConfig,这将启用属性路由以及使用 Web API 的默认路由模板的基于约定的路由。默认模板不会根据动作名称匹配,它仅根据控制器名称和请求的 HTTP 方法(GET、POST 等)匹配。示例 GET http://localhost:5000/api/books/2 将路由到 BooksController 并将调用与命名约定匹配的操作方法,即 GetBookById(int id)。

config.MapHttpAttributeRoutes();

config.Routes.MapHttpRoute(
    name: "DefaultApi",
    routeTemplate: "api/{controller}/{id}",
    defaults: new { id = RouteParameter.Optional }
);

在您的情况下,您有一个名为 DumpIntoFile(string data) 的操作方法,它不遵循上述标准命名约定,因此路由系统不知道要调用哪个操作。您可以使用在配置中启用的属性路由来解决此问题。您需要向您的操作方法添加一个属性,该属性指定 HTTP 动词以及应该调用该方法的路由。请注意应该添加到控制器类的附加属性,它指定路由前缀。

[RoutePrefix("api/warehouse")]
public class WarehouseController : ApiController
{
    // Routes POST http://localhost:5000/api/warehouse/dump
    [Route("dump")]
    [HttpPost]
    public bool DumpIntoFile(string data)
    {
        //...
    }
}

这会将 POST 请求路由到 http://localhost:5000/api/warehouse/dump。显然,localhost:5000 是一个占位符,表示您的基本 uri 将是什么。我不知道您在请求中的data 有多复杂,但您可以参考有关如何处理请求正文中的数据的文档。该示例主要关注路由部分。

这只是一个简单的示例,您可以使用各种不同的属性来指定路由、接受的方法等。文档很好地概述了它并提供了大量示例。下面提供了链接。另外,我建议返回 IHttpActionResult 或 HttpResponseMessage 类型之一,而不是简单的 bool/string/int/etc。它只是为您返回的 HTTP 响应类型提供了更多选项,这些也在文档中。

文档:https://docs.microsoft.com/en-us/aspnet/web-api/overview/web-api-routing-and-actions/attribute-routing-in-web-api-2

【讨论】:

  • 而不是为控制器类和属性Route指示属性RoutePrefix和为动作方法DumpIntoFile指示动词httpPost,是否与在webapiconfig.cs文件中指示以下配置相同? config.Routes.MapHttpRoute(name: "WarehouseController", routeTemplate: "api/{controller}/{action}/{data}" );不需要分别在控制器和动作方法中指定这些属性和verd?
  • 我正在使用 ASP.NET Framework 4.5 和 Web API 2.2 版本 5.2.3。我已经提供了安装在其中的 nuget 包的屏幕截图。查看更新后的帖子。
  • 关于action方法DumpIntoFile中作为字符串传递的数据,是类对象: public class Warehouse { public DataTable dt { get;放; } 公共字符串文件路径 { 获取;放; } } 之前发出请求 client.PostAsync("api/Warehouse/DumpIntoFile", httpContent);它使用 Newtonsoft.JsonConvert.SerializeObject(myData); 进行序列化然后它被封装成一个 httpContent 作为 application/json 类型。 Web api 方法 DumpIntoFile 将其作为字符串接收并反序列化: JsonConvert.DeserializeObject(data);
  • @Ralph 关于RoutePrefix 属性,是的,我很确定您需要将其与HttpPost 和Route 属性一起包含在操作方法中。据我了解,它将使用一个或另一个,基于属性或基于约定。不是两者的混合。至于您的数据结构,您需要接受一个与您的数据结构相匹配的参数,即DumpIntoFile(Warehouse data) 或您通过请求正文传递的任何特定对象。正如您所提到的,您可能可以使用DeserializeObject<Warehouse>,这取决于。
  • @Ralph 我建议参考文档以获取更具体的信息。我建议自己使用属性路由,因为它更简单,并且为您定义控制器操作路由提供了更大的灵活性。 docs.microsoft.com/en-us/aspnet/web-api/overview/…
【解决方案2】:

可能的看点:

  1. 检查您的 WebApi 文档。 Web API 中的 404 表示主机不可访问或您调用的端点错误。首先通过在浏览器中粘贴 URL 来检查。如果它是 POST 操作并且您的机器可以访问,那么您将收到 method not supported 错误。

  2. 如果在浏览器中,如果它再次出现 404 但您知道它是正确的,那么您应该查看机器的 ACL(用户授权和身份验证)。该机器是否可访问/可访问您的网络。

  3. 我在您的代码中看不到任何授权标头。也请检查一下。

  4. 几乎不可能 - 如果它需要一些预配置的应用程序,如 Facebook、Google 等。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-10-19
    • 1970-01-01
    • 2020-09-07
    • 1970-01-01
    • 2015-08-07
    • 1970-01-01
    • 1970-01-01
    • 2016-01-25
    相关资源
    最近更新 更多