Skip to content

Repository files navigation

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:

PackageRoleTarget Frameworks
VirusScanner.CoreAbstractions only – IVirusScanner, IBatchProcessor, shared models. No external dependencies.netstandard2.0, netstandard2.1, net10.0
VirusScanner.ClamAVClamAV 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

usingVirusScanner.ClamAV;usingVirusScanner.Core;varscanner=newClamAvScanner("localhost",3310);// Check connectivityboolisReady=awaitscanner.TryPingAsync();// Scan a fileScanResultresult=awaitscanner.ScanAsync(@"C:\test.txt");switch(result.Status){caseScanStatus.Clean:Console.WriteLine("The file is clean!");break;caseScanStatus.VirusDetected:Console.WriteLine($"Virus found: {result.InfectedFiles![0].VirusName}");break;caseScanStatus.Error:Console.WriteLine("Scan error.");break;}

You can also construct ClamAvScanner with an IPAddress:

varscanner=newClamAvScanner(IPAddress.Parse("127.0.0.1"),3310);

Scanning Overloads

ClamAvScanner implements IVirusScanner and supports scanning from multiple sources:

// From a file pathScanResultresult=awaitscanner.ScanAsync(@"C:\test.txt");// From a streamawaitusingvarstream=File.OpenRead(@"C:\test.txt");ScanResultresult=awaitscanner.ScanAsync(stream);// From a byte arraybyte[]data=awaitFile.ReadAllBytesAsync(@"C:\test.txt");ScanResultresult=awaitscanner.ScanAsync(data);

ClamAV-specific Operations

// PING – throws if the server does not respond with PONGawaitscanner.PingAsync();// TryPing – returns false instead of throwingboolavailable=awaitscanner.TryPingAsync();// Server version stringstringversion=awaitscanner.GetVersionAsync();// Server statsstringstats=awaitscanner.GetStatsAsync();

Batch Processing

VirusScanner.ClamAV includes batch processing for scanning multiple files efficiently.

Extension Methods (simplest)

// Scan a list of filesIEnumerable<BatchScanResult>results=awaitscanner.BatchScanFilesAsync(filePaths);// Scan a directoryIEnumerable<BatchScanResult>results=awaitscanner.BatchScanDirectoryAsync(@"C:\MyFolder",recursive:true);// Scan by file extensionsIEnumerable<BatchScanResult>results=awaitscanner.BatchScanByExtensionsAsync(@"C:\MyFolder",new[]{".exe",".dll"});// Scan executable files onlyIEnumerable<BatchScanResult>results=awaitscanner.BatchScanExecutableFilesAsync(@"C:\MyFolder",recursive:true);

ClamAvBatchProcessor (more control)

varprocessor=newClamAvBatchProcessor(scanner,maxConcurrency:4,connectionTimeoutSeconds:10);IEnumerable<BatchScanResult>results=awaitprocessor.ScanDirectoryAsync(@"C:\MyFolder",recursive:true);

Progress Reporting

varprogress=newProgress<BatchProgress>(p =>{Console.WriteLine($"Progress: {p.CompletedFiles}/{p.TotalFiles} ({p.PercentageComplete:F1}%)");Console.WriteLine($"Current: {p.CurrentFile}");});varresults=awaitscanner.BatchScanDirectoryAsync(@"C:\MyFolder",recursive:true,progressCallback:progress);

Result Analysis

// Generate a detailed text reportstringreport=ClamAvBatchUtilities.GenerateReport(results,DateTime.Now);// Filter resultsvarinfected=results.Where(r =>r.IsInfected);varerrors=results.Where(r =>r.HasError);varclean=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

ProjectDescription
VirusScanner.CoreAbstractions: IVirusScanner, IBatchProcessor, ScanResult, ScanStatus, BatchScanResult, BatchProgress, InfectedFile, ScanException
VirusScanner.ClamAVClamAV implementation: ClamAvScanner, IClamAvScanner, ClamAvBatchProcessor, ClamAvBatchExtensions, ClamAvBatchUtilities
VirusScanner.ConsoleTestInteractive console test application
VirusScanner.TestsUnit 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.

usingSystem.IO;usingSystem.Threading;usingSystem.Threading.Tasks;usingVirusScanner.Core;// Example: a provider that delegates to a proprietary REST APIpublicclassMyRestScanner:IVirusScanner{publicTask<bool>IsAvailableAsync(CancellationTokencancellationToken=default)=>/* call health endpoint */Task.FromResult(true);publicTask<ScanResult>ScanAsync(byte[]data,CancellationTokencancellationToken=default)=>ScanAsync(newMemoryStream(data),cancellationToken);publicasyncTask<ScanResult>ScanAsync(Streamdata,CancellationTokencancellationToken=default){// send stream to your API, parse responsereturnnewScanResult(ScanStatus.Clean);}publicasyncTask<ScanResult>ScanAsync(stringfilePath,CancellationTokencancellationToken=default){awaitusingvarstream=File.OpenRead(filePath);returnawaitScanAsync(stream,cancellationToken);}}

Register it exactly like the built-in ClamAV provider:

// ASP.NET Core – swap the implementation without changing any other codebuilder.Services.AddScoped<IVirusScanner,MyRestScanner>();// orbuilder.Services.AddScoped<IVirusScanner,ClamAvScanner>(_ =>newClamAvScanner("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.

About

VirusScanner offers a fast, lightweight, and protocol-native way to scan files, directories, and streams by directly interacting with a ClamAV daemon via the official clamd protocol, no wrappers, just pure performance and control.

Resources

Stars

5 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages