HttpClient-此实例已经启动 [英] HttpClient - This instance has already started

查看:319
本文介绍了HttpClient-此实例已经启动的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在api中使用http客户端获取了此异常.

I'm getting this exception using http client in my api.

执行请求时发生未处理的异常. System.InvalidOperationException:该实例已经启动了一个或多个请求.只能在发送第一个请求之前修改属性.

An unhandled exception has occurred while executing the request. System.InvalidOperationException: This instance has already started one or more requests. Properties can only be modified before sending the first request.

我以

services.AddSingleton<HttpClient>()

我认为单身是我最好的

I thought singleton was my best bet. what could be my problem?

编辑:我的用法

class ApiClient
{
   private readonly HttpClient _client;
   public ApiClient(HttpClient client)
   {
      _client = client;
   }

   public async Task<HttpResponseMessage> GetAsync(string uri)
   {
     _client.BaseAddress = new Uri("http://localhost:5001/");
     _client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json");
     var response = await _client.GetAsync(uri);

     return response;
   }
 }

推荐答案

这是类这里有趣的方法是CheckDisposedOrStarted().

private void CheckDisposedOrStarted()
{
     CheckDisposed();
     if (_operationStarted)
     {
         throw new InvalidOperationException(SR.net_http_operation_started);
     }
}

现在在设置属性时会调用

Now this is called when setting the properties

  1. BaseAddress
  2. Timeout
  3. MaxResponseContentBufferSize
  1. BaseAddress
  2. Timeout
  3. MaxResponseContentBufferSize

因此,如果您打算重复使用HttpClient实例,则应设置一个实例来预置这3个属性,并且所有使用都必须不要修改这些属性.

So if you are planning to reuse the HttpClient instance you should setup a single instance that presets those 3 properties and all uses must NOT modify these properties.

或者,您可以创建工厂或使用简单的AddTransient(...).请注意,AddScoped在这里并不是最合适的,因为您将在每个请求范围内收到相同的实例.

Alternativly you can create a factory or use simple AddTransient(...). Note that AddScoped is not best suited here as you will recieve the same instance per request scope.

编辑基本工厂

现在,工厂不过是负责为另一个服务提供实例的服务.这是一个构建HttpClient的基本工厂,现在意识到这只是您可以扩展该工厂要做的最基本的工作,并预设HttpClient

Now a factory is nothing more than a service that is responsible for providing an instance to another service. Here is a basic factory to build your HttpClient now realize this is only the most basic you can extend this factory to do as you wish and presetup every instance of the HttpClient

public interface IHttpClientFactory
{
    HttpClient CreateClient();
}

public class HttpClientFactory : IHttpClientFactory
{
    static string baseAddress = "http://example.com";

    public HttpClient CreateClient()
    {
        var client = new HttpClient();
        SetupClientDefaults(client);
        return client;
    }

    protected virtual void SetupClientDefaults(HttpClient client)
    {
        client.Timeout = TimeSpan.FromSeconds(30); //set your own timeout.
        client.BaseAddress = new Uri(baseAddress);
    }
}

现在为什么要使用和界面?这是通过使用依赖项注入和IoC来完成的,我们可以轻松地非常轻松地交换"应用程序的各个部分.现在,我们不再尝试访问HttpClientFactory,而是访问IHttpClientFactory.

Now why did I use and interface? This is done as using dependency injection and IoC we can easily "swap" parts of the application out very easily. Now instead of trying to access the HttpClientFactory we access the IHttpClientFactory.

services.AddScoped<IHttpClientFactory, HttpClientFactory>();

现在,在您的类,服务或控制器中,您将请求工厂接口并生成一个实例.

Now in your class, service or controller you would request the factory interface and generate an instance.

public HomeController(IHttpClientFactory httpClientFactory)
{
    _httpClientFactory = httpClientFactory;
}

readonly IHttpClientFactory _httpClientFactory;

public IActionResult Index()
{
    var client = _httpClientFactory.CreateClient();
    //....do your code
    return View();
}

关键在这里.

  1. 工厂负责生成客户端实例,并将管理默认值.
  2. 我们正在请求接口而不是实现.这有助于我们使组件保持断开连接,并允许进行更多的模块化设计.
  3. 该服务已注册为作用域实例.单例有其用途,但在这种情况下,您更有可能需要作用域实例.

范围内的生命周期服务每个请求创建一次.

Scoped lifetime services are created once per request.

这篇关于HttpClient-此实例已经启动的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆