在没有启动的情况下在较旧的ASP.NET MVC应用程序中创建HttpClient

Sam*_*Sam 6 c# asp.net asp.net-mvc asp.net-mvc-4

我有一个旧版本的ASP.NET MVC应用程序没有Startup.cs.我想实现一种干净的方式,HttpClient以便我可以使用我的API调用第三方.

这是我到目前为止基于我收到的关于这个问题的一些想法/建议所做的.问题是,当我进行API调用时,它无处可去.我把它放在一个try catch但我甚至没有得到例外.API提供商告诉我他们没有看到搜索参数.

首先,我HttpClientAccessor为延迟加载创建了这个.

public static class HttpClientAccessor
{
   public static Func<HttpClient> ValueFactory = () =>
   {
      var client = new HttpClient();

      client.BaseAddress = new Uri("https://apiUrl.com");
      client.DefaultRequestHeaders.Accept.Clear();
      client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
      client.DefaultRequestHeaders.TryAddWithoutValidation("APIAccessToken", "token1");
      client.DefaultRequestHeaders.TryAddWithoutValidation("UserToken", "token2");

       return client;
   };

   private static Lazy<HttpClient> client = new Lazy<HttpClient>(ValueFactory);

   public static HttpClient HttpClient
   {
      get { return client.Value; }
   }
}
Run Code Online (Sandbox Code Playgroud)

然后我创建了一个自己的API客户端,以便我可以在一个地方使用API​​调用函数,如下所示:

public class MyApiClient
{

   public async Task GetSomeData()
   {
       var client = HttpClientAccessor.HttpClient;
       try
       {
           var result = await client.GetStringAsync("somedata/search?text=test");
           var output = JObject.Parse(result);
       }
       catch(Exception e)
       {
           var error = e.Message;
       }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后在我的ASP.NET控制器操作中,我这样做:

public class MyController : Controller
{
   private static readonly MyApiClient _apiClient = new MyApiClient ();

   public ActionResult ApiTest()
   {
       var data = _apiClient.GetSomeData().Wait();
   }
}
Run Code Online (Sandbox Code Playgroud)

知道我的错误在哪里?

更新:这个简单的方法工作正常:

public class MyController : Controller
{
   private static readonly HttpClient _client = new HttpClient();

   public ActionResult ApiTest()
   {
       _client.BaseAddress = new Uri("https://apiUrl.com");
       _client.DefaultRequestHeaders.Accept.Clear();
       _client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
       _client.DefaultRequestHeaders.TryAddWithoutValidation("APIAccessToken", "token1");
       _client.DefaultRequestHeaders.TryAddWithoutValidation("UserToken", "token2");

       var response = _client.GetStringAsync("somedata/search?text=test").Result;
   }
}
Run Code Online (Sandbox Code Playgroud)

Nko*_*osi 5

如上所述,依赖注入没有被利用,因此从技术上讲,不需要组合根,这些东西将被初始化.

如果在启动时无需实际初始化客户端,则可以考虑使用Lazy单例方法.

一个例子

public static class HttpClientAccessor {
   public static Func<HttpClient> ValueFactory = () => {
      var client = new HttpClient();

      client.BaseAddress = new Uri("https://apiUrl.com");
      client.DefaultRequestHeaders.Accept.Clear();
      client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
      client.DefaultRequestHeaders.TryAddWithoutValidation("APIAccessToken", "token1");
      client.DefaultRequestHeaders.TryAddWithoutValidation("UserToken", "token2");

       return client;
   };

   private static Lazy<HttpClient> client = new Lazy<HttpClient>(ValueFactory);

   public static HttpClient HttpClient {
      get { return client.Value; }
   }
}
Run Code Online (Sandbox Code Playgroud)

Lazy<HttpClient>如果客户端需要其他设置,则可以使工厂代表更复杂.

无论客户需要哪个地方,您都可以致电该服务

var client = HttpClientAccessor.HttpClient;

var response = await client.GetStringAsync("{url}");
Run Code Online (Sandbox Code Playgroud)

客户端将在首次使用时初始化,您将在后续的实例调用中获得相同的实例.

在控制器中使用时,您将异步调用与阻塞调用行.Wait().Result.这可能导致死锁,应该避免.

public class MyController : Controller {
    private static readonly MyApiClient _apiClient = new MyApiClient ();

    public async Task<ActionResult> ApiTest() {
        var data = await _apiClient.GetSomeData();

        //...
    }
}
Run Code Online (Sandbox Code Playgroud)

代码应该始终是异步的.

参考Async/Await - 异步编程的最佳实践

  • `Lazy`是线程安全的,`HttpClient`也是线程安全的 (2认同)