Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

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

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.

and I injected my service as

services.AddSingleton<HttpClient>()

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

edit: my usage

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;
   }
 }
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
1.5k views
Welcome To Ask or Share your Answers For Others

1 Answer

This is the design of the class HttpClient .Net Core Source.

The interesting method here is the 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

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.

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.

Edit Basic Factory

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);
    }
}

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();
}

The key here is.

  1. The factory is responsible for generating the client instance and will manage the defaults.
  2. We are requesting the interface not the implementation. This helps us keep our components disconnected and allow for a more modular design.
  3. The service is registered as a Scoped instance. Singletons have their uses but in this case you are more likely to want a scoped instance.

Scoped lifetime services are created once per request.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...