VirusScanner.ClamAV 1.0.0

dotnet add package VirusScanner.ClamAV --version 1.0.0
                    
NuGet\Install-Package VirusScanner.ClamAV -Version 1.0.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="VirusScanner.ClamAV" Version="1.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="VirusScanner.ClamAV" Version="1.0.0" />
                    
Directory.Packages.props
<PackageReference Include="VirusScanner.ClamAV" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add VirusScanner.ClamAV --version 1.0.0
                    
#r "nuget: VirusScanner.ClamAV, 1.0.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package VirusScanner.ClamAV@1.0.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=VirusScanner.ClamAV&version=1.0.0
                    
Install as a Cake Addin
#tool nuget:?package=VirusScanner.ClamAV&version=1.0.0
                    
Install as a Cake Tool

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.Core and code against IVirusScanner.
  • Applications that use ClamAV → install only VirusScanner.ClamAV. VirusScanner.Core is 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):

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 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

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