VirusScanner.ClamAV
1.0.0
dotnet add package VirusScanner.ClamAV --version 1.0.0
NuGet\Install-Package VirusScanner.ClamAV -Version 1.0.0
<PackageReference Include="VirusScanner.ClamAV" Version="1.0.0" />
<PackageVersion Include="VirusScanner.ClamAV" Version="1.0.0" />
<PackageReference Include="VirusScanner.ClamAV" />
paket add VirusScanner.ClamAV --version 1.0.0
#r "nuget: VirusScanner.ClamAV, 1.0.0"
#:package VirusScanner.ClamAV@1.0.0
#addin nuget:?package=VirusScanner.ClamAV&version=1.0.0
#tool nuget:?package=VirusScanner.ClamAV&version=1.0.0
VirusScanner
A .NET library for virus scanning with a provider-agnostic design. VirusScanner.Core defines the interfaces and models; any backend can implement them. VirusScanner.ClamAV ships the first-party ClamAV provider. Licensed under the MIT License.
Packages
Two NuGet packages are published from this repository:
| Package | Role | Target Frameworks |
|---|---|---|
VirusScanner.Core |
Abstractions only – IVirusScanner, IBatchProcessor, shared models. No external dependencies. |
netstandard2.0, netstandard2.1, net10.0 |
VirusScanner.ClamAV |
ClamAV provider – implements IVirusScanner against a clamd server. Depends on VirusScanner.Core. |
netstandard2.0, netstandard2.1, net10.0 |
Which package do I need?
- Libraries / shared code that should stay backend-independent → install only
VirusScanner.Coreand code againstIVirusScanner. - Applications that use ClamAV → install only
VirusScanner.ClamAV.VirusScanner.Coreis pulled in automatically as a transitive dependency.
# Application – one package is enough, Core comes along automatically
Install-Package VirusScanner.ClamAV
# Library / shared project – abstractions only, no backend coupling
Install-Package VirusScanner.Core
ClamAV Dependency
A running ClamAV (clamd) server is required. ClamAV is a free, open-source virus scanner.
Current stable release lines (as of 2026-03):
1.5.x (latest: 1.5.2)
1.4.x (latest: 1.4.4)
1.0.x LTS (latest: 1.0.9)
Docs: https://docs.clamav.net/
Communication uses the standard clamd protocol commands PING, VERSION, and INSTREAM, so VirusScanner is compatible with any current ClamAV release that supports the clamd protocol.
Docker Compose
This repository includes a ready-to-use docker-compose.yml to run ClamAV locally.
# Start ClamAV
docker compose up -d
# Follow logs until clamd is ready
docker compose logs -f clamav
# Stop
docker compose down
Connection settings:
- .NET app running on the host machine →
localhost:3310 - .NET app running as a Compose service in the same network →
clamav:3310
Quick Start
using VirusScanner.ClamAV;
using VirusScanner.Core;
var scanner = new ClamAvScanner("localhost", 3310);
// Check connectivity
bool isReady = await scanner.TryPingAsync();
// Scan a file
ScanResult result = await scanner.ScanAsync(@"C:\test.txt");
switch (result.Status)
{
case ScanStatus.Clean:
Console.WriteLine("The file is clean!");
break;
case ScanStatus.VirusDetected:
Console.WriteLine($"Virus found: {result.InfectedFiles![0].VirusName}");
break;
case ScanStatus.Error:
Console.WriteLine("Scan error.");
break;
}
You can also construct ClamAvScanner with an IPAddress:
var scanner = new ClamAvScanner(IPAddress.Parse("127.0.0.1"), 3310);
Scanning Overloads
ClamAvScanner implements IVirusScanner and supports scanning from multiple sources:
// From a file path
ScanResult result = await scanner.ScanAsync(@"C:\test.txt");
// From a stream
await using var stream = File.OpenRead(@"C:\test.txt");
ScanResult result = await scanner.ScanAsync(stream);
// From a byte array
byte[] data = await File.ReadAllBytesAsync(@"C:\test.txt");
ScanResult result = await scanner.ScanAsync(data);
ClamAV-specific Operations
// PING – throws if the server does not respond with PONG
await scanner.PingAsync();
// TryPing – returns false instead of throwing
bool available = await scanner.TryPingAsync();
// Server version string
string version = await scanner.GetVersionAsync();
// Server stats
string stats = await scanner.GetStatsAsync();
Batch Processing
VirusScanner.ClamAV includes batch processing for scanning multiple files efficiently.
Extension Methods (simplest)
// Scan a list of files
IEnumerable<BatchScanResult> results = await scanner.BatchScanFilesAsync(filePaths);
// Scan a directory
IEnumerable<BatchScanResult> results = await scanner.BatchScanDirectoryAsync(
@"C:\MyFolder", recursive: true);
// Scan by file extensions
IEnumerable<BatchScanResult> results = await scanner.BatchScanByExtensionsAsync(
@"C:\MyFolder", new[] { ".exe", ".dll" });
// Scan executable files only
IEnumerable<BatchScanResult> results = await scanner.BatchScanExecutableFilesAsync(
@"C:\MyFolder", recursive: true);
ClamAvBatchProcessor (more control)
var processor = new ClamAvBatchProcessor(scanner, maxConcurrency: 4, connectionTimeoutSeconds: 10);
IEnumerable<BatchScanResult> results = await processor.ScanDirectoryAsync(
@"C:\MyFolder", recursive: true);
Progress Reporting
var progress = new Progress<BatchProgress>(p =>
{
Console.WriteLine($"Progress: {p.CompletedFiles}/{p.TotalFiles} ({p.PercentageComplete:F1}%)");
Console.WriteLine($"Current: {p.CurrentFile}");
});
var results = await scanner.BatchScanDirectoryAsync(
@"C:\MyFolder",
recursive: true,
progressCallback: progress);
Result Analysis
// Generate a detailed text report
string report = ClamAvBatchUtilities.GenerateReport(results, DateTime.Now);
// Filter results
var infected = results.Where(r => r.IsInfected);
var errors = results.Where(r => r.HasError);
var clean = results.Where(r => r.IsClean);
Batch Processing Features
- Concurrent scanning – configurable degree of parallelism
- Progress tracking – real-time
IProgress<BatchProgress>callbacks - Directory scanning – recursive and non-recursive
- File filtering – by extension or predefined categories
- Connection resilience – graceful handling of daemon disconnections
- Configurable timeouts – prevent hanging operations
- Report generation – built-in text report via
ClamAvBatchUtilities
Project Structure
| Project | Description |
|---|---|
VirusScanner.Core |
Abstractions: IVirusScanner, IBatchProcessor, ScanResult, ScanStatus, BatchScanResult, BatchProgress, InfectedFile, ScanException |
VirusScanner.ClamAV |
ClamAV implementation: ClamAvScanner, IClamAvScanner, ClamAvBatchProcessor, ClamAvBatchExtensions, ClamAvBatchUtilities |
VirusScanner.ConsoleTest |
Interactive console test application |
VirusScanner.Tests |
Unit and integration tests |
Custom Providers
Because all consuming code depends only on IVirusScanner from VirusScanner.Core, you can swap or add any backend without touching the rest of your application.
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using VirusScanner.Core;
// Example: a provider that delegates to a proprietary REST API
public class MyRestScanner : IVirusScanner
{
public Task<bool> IsAvailableAsync(CancellationToken cancellationToken = default)
=> /* call health endpoint */ Task.FromResult(true);
public Task<ScanResult> ScanAsync(byte[] data, CancellationToken cancellationToken = default)
=> ScanAsync(new MemoryStream(data), cancellationToken);
public async Task<ScanResult> ScanAsync(Stream data, CancellationToken cancellationToken = default)
{
// send stream to your API, parse response
return new ScanResult(ScanStatus.Clean);
}
public async Task<ScanResult> ScanAsync(string filePath, CancellationToken cancellationToken = default)
{
await using var stream = File.OpenRead(filePath);
return await ScanAsync(stream, cancellationToken);
}
}
Register it exactly like the built-in ClamAV provider:
// ASP.NET Core – swap the implementation without changing any other code
builder.Services.AddScoped<IVirusScanner, MyRestScanner>();
// or
builder.Services.AddScoped<IVirusScanner, ClamAvScanner>(_ => new ClamAvScanner("localhost", 3310));
The same principle applies to IBatchProcessor – implement it to add batch support to any provider.
Contributing
PRs are welcome! See VirusScanner.ConsoleTest/Program.cs for a full usage example.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 is compatible. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- VirusScanner.Core (>= 1.0.0)
-
.NETStandard 2.1
- VirusScanner.Core (>= 1.0.0)
-
net10.0
- VirusScanner.Core (>= 1.0.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.0.0 | 71 | 3/28/2026 |