Skip to content

[BUG] Refit + Fusillade fails with System.ObjectDisposedException #148

Open
@JeremyBP

Description

@JeremyBP

Describe the bug
Actually the same as #34 witch is closed but not fixed.
Using Refit with Fusillade fails with System.ObjectDisposedException: Cannot access a disposed object. Object name: 'System.Net.Http.HttpConnectionResponseContent'.
The exception is thrown at Refit.RequestBuilderImplementation.d__15`1.MoveNext() in /_/Refit/RequestBuilderImplementation.cs:line 324
It seems that when Fusillade deduplicates requests returning val.Response.ToTask(cancellationToken), Refit fails deserializing HttpContent because it's disposed.

As @clairernovotny on the Refit side with issue #1048 think it looks like a Fusillade bug, I opened the same issue on the Fusillade side.
I don't know if the bug comes from Refit or Fusillade, but I know it throws when using one with each other.

Steps To Reproduce
Create a Refit RestService with any Fusillade's NetCache HttpMessageHandler into the HttpClient, and send the same request at least twice at the same time.
Something dummy like:

try
{
	var reqResService = RestService.For<IReqResService>(new HttpClient(NetCache.UserInitiated)
	{
		BaseAddress = new Uri("https://reqres.in/api")
	});

	var task1 = reqResService.GetUsersAsync();
	var task2 = reqResService.GetUsersAsync();

	var result = await Task.WhenAll(task1, task2);
	var userList = result.FirstOrDefault();
}
catch (Exception e)
{
	throw;
}

with IReqResService:

public interface IReqResService
{
	[Get("/users")]
	Task<UserList> GetUsersAsync();
}

and Models:

public class UserList
{
	[JsonProperty("page")]
	public int Page { get; set; }

	[JsonProperty("per_page")]
	public int PerPage { get; set; }

	[JsonProperty("total")]
	public int Total { get; set; }

	[JsonProperty("total_pages")]
	public int TotalPages { get; set; }

	[JsonProperty("data")]
	public List<User> Data { get; set; }
}

public class User
{
	[JsonProperty("id")]
	public int Id { get; set; }

	[JsonProperty("first_name")]
	public string FirstName { get; set; }

	[JsonProperty("last_name")]
	public string LastName { get; set; }

	[JsonProperty("avatar")]
	public string Avatar { get; set; }

	[JsonProperty("email")]
	public string Email { get; set; }
}

Well interface and models are not the point, it's just to illustrate the bug.
Note that everything succeed when using Fusillade without Refit, I mean using HttpClient directly like:

try
{
	var client = new HttpClient(NetCache.UserInitiated)
	{
		BaseAddress = new Uri("https://reqres.in/api/users")
	};

	var task1 = client.GetAsync("");
	var task2 = client.GetAsync("");

	var responses = await Task.WhenAll(task1, task2);
	var jsonString = await responses.First().Content.ReadAsStringAsync().ConfigureAwait(false);
	var userList = JsonConvert.DeserializeObject<UserList>(jsonString);
}
catch (Exception e)
{
	throw;
}

Note that everything succeed to, when using Refit without Fusillade like:

try
{
	var reqResService = RestService.For<IReqResService>("https://reqres.in/api");

	var task1 = reqResService.GetUsersAsync();
	var task2 = reqResService.GetUsersAsync();

	var result = await Task.WhenAll(task1, task2);
	var userList = result.FirstOrDefault();
}
catch (Exception e)
{
	throw;
}

So it's only when using both of it.

Expected behavior
Should return result

Environment

  • OS: All
  • Device: All
  • Version: All

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions