![]() |
VOOZH | about |
dotnet add package fusillade --version 5.0.0
NuGet\Install-Package fusillade -Version 5.0.0
<PackageReference Include="fusillade" Version="5.0.0" />
<PackageVersion Include="fusillade" Version="5.0.0" />Directory.Packages.props
<PackageReference Include="fusillade" />Project file
paket add fusillade --version 5.0.0
#r "nuget: fusillade, 5.0.0"
#:package fusillade@5.0.0
#addin nuget:?package=fusillade&version=5.0.0Install as a Cake Addin
#tool nuget:?package=fusillade&version=5.0.0Install as a Cake Tool
👁 NuGet Stats
👁 Build
👁 Code Coverage
<br /> <a href="https://github.com/reactiveui/fusillade"> <img width="120" heigth="120" src="https://raw.githubusercontent.com/reactiveui/styleguide/master/logo_fusillade/main.png"> </a>
Fusillade helps you write efficient, resilient networked apps by composing HttpMessageHandlers for HttpClient. It focuses on:
Design inspirations include Android's Volley and Picasso.
Supported targets: library is built for .NET 4.6.2+, .NET 8/9/10, for modern .Net applications.
Optional (examples below): Akavache for caching.
Create HttpClient instances by picking the right handler from NetCache:
using Fusillade;
using System.Net.Http;
// Highest priority: the user is waiting now
var client = new HttpClient(NetCache.UserInitiated);
var json = await client.GetStringAsync("https://httpbin.org/get");
Available built-ins:
By default, requests are processed four at a time via an operation queue.
Fusillade de-duplicates concurrent requests for the same resource when the method is GET, HEAD, or OPTIONS. If multiple callers request the same URL concurrently, only one on-the-wire request is made; the others join the same in-flight response.
This happens transparently in RateLimitedHttpMessageHandler.
All work is scheduled through an OperationQueue (default parallelism is 4). Each handler has an effective priority:
Higher numbers run before lower ones. You can set a custom base (Explicit) and an offset to fit your scenario.
using Fusillade;
using Punchclock;
using System.Net.Http;
// Custom queue with 2 concurrent slots
var queue = new OperationQueue(2);
var handler = new RateLimitedHttpMessageHandler(
new HttpClientHandler(),
basePriority: Priority.Explicit,
priority: 500, // higher runs earlier
opQueue: queue);
var client = new HttpClient(handler);
Use NetCache.Speculative for prefetching scenarios. Limit the total number of bytes fetched; once the limit is reached, further speculative requests are canceled.
// Reset byte budget to 5 MB (e.g., on app resume)
NetCache.Speculative.ResetLimit(5 * 1024 * 1024);
var prefetch = new HttpClient(NetCache.Speculative);
_ = prefetch.GetStringAsync("https://example.com/expensive-data");
To stop speculative fetching immediately:
NetCache.Speculative.ResetLimit(-1); // any further requests will be canceled
Fusillade can optionally cache responses (body bytes + headers) and replay them when offline.
There are two ways to wire caching:
Provide a cacheResultFunc to RateLimitedHttpMessageHandler, which gets called with the response and a unique request key when a response is received.
Set NetCache.RequestCache with an implementation of IRequestCache. Fusillade will invoke Save and Fetch automatically.
public interface IRequestCache
{
Task Save(HttpRequestMessage request, HttpResponseMessage response, string key, CancellationToken ct);
Task<byte[]> Fetch(HttpRequestMessage request, string key, CancellationToken ct);
}
Keys are generated by RateLimitedHttpMessageHandler.UniqueKeyForRequest(request). Treat the key as an implementation detail; persist what you receive and return it during Fetch.
using Akavache;
using Akavache.SystemTextJson;
using Fusillade;
using System.Net.Http;
// Initialize a simple in-memory Akavache cache
var database = CacheDatabase.CreateBuilder().WithSerializerSystemTextJson().Build();
var blobCache = new InMemoryBlobCache(database.Serializer);
// Option A: Provide a cacheResultFunc directly
var cachingHandler = new RateLimitedHttpMessageHandler(
new HttpClientHandler(),
Priority.UserInitiated,
cacheResultFunc: async (rq, resp, key, ct) =>
{
var data = await resp.Content.ReadAsByteArrayAsync(ct);
await blobCache.Insert(key, data);
});
var client = new HttpClient(cachingHandler);
var fresh = await client.GetStringAsync("https://httpbin.org/get");
// Option B: Implement IRequestCache and set NetCache.RequestCache
NetCache.RequestCache = new MyRequestCache(blobCache);
// Example IRequestCache wrapper over Akavache
class MyRequestCache : IRequestCache
{
private readonly IBlobCache _cache;
public MyRequestCache(IBlobCache cache) => _cache = cache;
public async Task Save(HttpRequestMessage request, HttpResponseMessage response, string key, CancellationToken ct)
{
var bytes = await response.Content.ReadAsByteArrayAsync(ct);
await _cache.Insert(key, bytes);
}
public Task<byte[]> Fetch(HttpRequestMessage request, string key, CancellationToken ct)
=> _cache.Get(key);
}
Use OfflineHttpMessageHandler to serve cached data only (no network). This handler asks IRequestCache (or your custom retrieveBodyFunc) for the cached body and returns:
// Use NetCache.Offline after setting NetCache.RequestCache
var offline = new HttpClient(NetCache.Offline);
var data = await offline.GetStringAsync("https://httpbin.org/get");
// Or construct explicitly
var offlineExplicit = new HttpClient(new OfflineHttpMessageHandler(
async (rq, key, ct) => await blobCache.Get(key)));
If you use Splat, you can initialize NetCache to use your container’s services via the provided extension:
using Splat.Builder;
var app = AppBuilder.CreateSplatBuilder().Build();
app.CreateFusilladeNetCache();
You can also register a platform-specific HttpMessageHandler (e.g., NSUrlSessionHandler on iOS, AndroidMessageHandler on Android) in your container beforehand; NetCache will pick it up as the inner HTTP handler.
using Punchclock;
NetCache.OperationQueue = new OperationQueue(maxConcurrency: 6);
var urgent = new RateLimitedHttpMessageHandler(new HttpClientHandler(), Priority.Explicit, priority: 1_000);
var slow = new RateLimitedHttpMessageHandler(new HttpClientHandler(), Priority.Explicit, priority: -50);
Image gallery / avatars
Boot-time warmup
Offline-first data views
How many requests run at once?
Which methods are de-duplicated?
How are cache keys generated?
Can I cancel a request?
Fusillade is developed under an OSI-approved open source license, making it freely usable and distributable, even for commercial use. We ❤ our contributors and welcome new contributors of all experience levels.
“Fusillade” is a synonym for Volley 🙂
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 net8.0 is compatible. net8.0-android net8.0-android was computed. net8.0-browser net8.0-browser was computed. net8.0-ios net8.0-ios was computed. net8.0-maccatalyst net8.0-maccatalyst was computed. net8.0-macos net8.0-macos was computed. net8.0-tvos net8.0-tvos was computed. net8.0-windows net8.0-windows was computed. net9.0 net9.0 is compatible. net9.0-android net9.0-android was computed. net9.0-browser net9.0-browser was computed. net9.0-ios net9.0-ios was computed. net9.0-maccatalyst net9.0-maccatalyst was computed. net9.0-macos net9.0-macos was computed. net9.0-tvos net9.0-tvos was computed. net9.0-windows net9.0-windows was computed. net10.0 net10.0 is compatible. net10.0-android net10.0-android was computed. net10.0-browser net10.0-browser was computed. net10.0-ios net10.0-ios was computed. net10.0-maccatalyst net10.0-maccatalyst was computed. net10.0-macos net10.0-macos was computed. net10.0-tvos net10.0-tvos was computed. net10.0-windows net10.0-windows was computed. |
| .NET Framework | net462 net462 is compatible. net463 net463 was computed. net47 net47 was computed. net471 net471 was computed. net472 net472 is compatible. net48 net48 was computed. net481 net481 is compatible. |
Showing the top 5 NuGet packages that depend on fusillade:
| Package | Downloads |
|---|---|
|
BD.Common.Mvvm
次元超越 Mvvm 库 |
|
|
ModSink.Common
This library contains most of the logic for ModSink. |
|
|
XamBasePacket
Includes all needed classes models and libs to start developing Xamarin application. |
|
|
Apizr.Integrations.Fusillade
Refit based web api client management, but resilient (retry, connectivity, cache, auth, log, priority...) |
|
|
Xablu.WebApiClient
The Xablu WebApiClient is a C# HTTP library which aims to simplify consuming of Web API services in .NET projects. |
Showing the top 4 popular GitHub repositories that depend on fusillade:
| Repository | Stars |
|---|---|
|
BeyondDimension/SteamTools
🛠「Watt Toolkit」是一个开源跨平台的多功能 Steam 工具箱。
|
|
|
reactiveui/ReactiveUI.Samples
This repository contains ReactiveUI samples.
|
|
|
HTBox/crisischeckin
Crisischeckin Humanitarian Toolbox repository
|
|
|
Respawnsive/Apizr
Refit based web api client management, but resilient (retry, connectivity, cache, auth, log, priority, etc...)
|
| Version | Downloads | Last Updated |
|---|---|---|
| 5.0.0 | 163 | 5/23/2026 |
| 4.0.3 | 1,740 | 12/7/2025 |
| 4.0.1 | 360 | 11/30/2025 |
| 3.0.1 | 1,217 | 9/3/2025 |
| 2.6.30 | 29,541 | 5/2/2024 |
| 2.6.1 | 11,110 | 9/21/2023 |
| 2.4.67 | 24,190 | 2/1/2023 |
| 2.4.62 | 3,215 | 11/24/2022 |
| 2.4.47 | 4,648 | 6/22/2022 |
| 2.4.1 | 14,862 | 12/13/2021 |
| 2.3.1 | 33,385 | 1/22/2021 |
| 2.2.9 | 3,359 | 11/27/2020 |
| 2.2.1 | 2,738 | 10/23/2020 |
| 2.1.9 | 13,759 | 7/29/2020 |
| 2.1.1 | 29,677 | 5/10/2020 |
| 2.0.5 | 101,669 | 4/2/2019 |
| 2.0.2 | 4,037 | 2/19/2019 |
| 2.0.1 | 5,832 | 2/5/2019 |
| 1.0.0 | 52,919 | 9/5/2017 |
| 0.7.0 | 44,399 | 11/10/2016 |