A modern, cross-platform .NET library for NFC (Near Field Communication) operations using PC/SC (Personal Computer/Smart Card) technology.
- Cross-platform support: Works on Windows, macOS, and Linux
- Modern .NET: Built with .NET 6+ and .NET Standard 2.1
- Async/await support: All operations are asynchronous for better performance
- Event-driven architecture: Real-time card insertion/removal detection
- Comprehensive error handling: Proper exception handling and logging
- Extensible design: Interface-based architecture for easy testing and mocking
- PC/SC integration: Uses industry-standard PC/SC for reliable smart card communication
- .NET 6.0 or later
- PC/SC service running on your system
- NFC reader hardware (USB, Bluetooth, or built-in)
- Windows: Windows Smart Card service (usually enabled by default)
- macOS: PCSC-Lite (install via Homebrew:
brew install pcsc-lite) - Linux: PCSC-Lite (install via package manager:
sudo apt-get install pcscdon Ubuntu/Debian)
dotnet add package NFCReadergit clone https://github.com/h4kbas/nfc-reader.git
cd nfc-reader
dotnet restore
dotnet buildusing NFCReader;
using Microsoft.Extensions.Logging;
// Create logger (optional)
using var loggerFactory = LoggerFactory.Create(builder => builder.AddConsole());
var logger = loggerFactory.CreateLogger<Program>();
// Create NFC reader instance
using var nfcReader = new NFCReader(logger);
// Get available readers
var readers = await nfcReader.GetReadersAsync();
var firstReader = readers.FirstOrDefault(r => r.IsAvailable);
if (firstReader != null)
{
// Connect to reader
var connected = await nfcReader.ConnectAsync(firstReader.Name);
if (connected)
{
// Read card UID
var uid = await nfcReader.GetCardUIDAsync();
Console.WriteLine($"Card UID: {uid}");
}
}// Set up event handlers
nfcReader.CardInserted += (sender, card) =>
{
Console.WriteLine($"Card inserted: {card.FormattedUID}");
};
nfcReader.CardRemoved += (sender, card) =>
{
Console.WriteLine($"Card removed: {card.FormattedUID}");
};
// Start monitoring
await nfcReader.StartMonitoringAsync();// Read data from a block
var blockData = await nfcReader.ReadBlockAsync(4);
if (blockData != null)
{
Console.WriteLine($"Block data: {BitConverter.ToString(blockData)}");
}
// Write data to a block
var data = Encoding.UTF8.GetBytes("Hello NFC!");
var success = await nfcReader.WriteBlockAsync(5, data);
// Custom APDU command
var command = new APDUCommand
{
CLA = 0xFF,
INS = 0xCA,
P1 = 0x00,
P2 = 0x00,
Le = 0x00
};
var response = await nfcReader.TransmitAsync(command);
if (response.IsSuccess)
{
Console.WriteLine($"Response: {response.DataAsHex}");
}Main class for NFC operations.
Properties:
IsConnected: Gets whether the reader is connectedCurrentCard: Gets the currently connected cardReaderInfo: Gets current reader information
Methods:
ConnectAsync(): Connect to the first available readerConnectAsync(string readerName): Connect to a specific readerDisconnectAsync(): Disconnect from the current readerGetReadersAsync(): Get list of available readersTransmitAsync(APDUCommand): Send APDU command to cardGetCardUIDAsync(): Get card's unique identifierReadBlockAsync(byte blockNumber): Read data from a blockWriteBlockAsync(byte blockNumber, byte[] data): Write data to a blockAuthenticateBlockAsync(byte blockNumber): Authenticate a blockStartMonitoringAsync(): Start monitoring for card changesStopMonitoringAsync(): Stop monitoring for card changes
Events:
CardInserted: Raised when a card is insertedCardRemoved: Raised when a card is removedReaderStateChanged: Raised when reader state changes
Represents an APDU (Application Protocol Data Unit) command.
Properties:
CLA: Class byteINS: Instruction byteP1,P2: Parameter bytesData: Command dataLe: Expected response length
Static Methods:
GetUID: Creates a GET UID commandReadBlock(byte blockNumber): Creates a READ BLOCK commandWriteBlock(byte blockNumber, byte[] data): Creates a WRITE BLOCK commandAuthenticateBlock(byte blockNumber): Creates an AUTHENTICATE BLOCK command
Represents an APDU response from the card.
Properties:
Data: Response dataStatusWord: Status word (SW1 + SW2)IsSuccess: Whether the command was successfulStatusDescription: Human-readable status descriptionDataAsHex: Data as hexadecimal stringDataAsString: Data as UTF-8 string
Static utility methods for common operations:
ToHexString(): Convert bytes to hex stringFromHexString(): Convert hex string to bytesToUtf8String(): Convert bytes to UTF-8 stringToUtf8Bytes(): Convert string to UTF-8 bytesPadToLength(): Pad byte array to specified lengthTrimPadding(): Remove padding bytesCalculateCRC16(): Calculate CRC16 checksumFormatBytes(): Format bytes in various formats
The library includes comprehensive unit tests that can run without NFC hardware:
cd Tests
dotnet testTests use mocking to simulate NFC operations, making them suitable for CI/CD pipelines.
See the Examples/ directory for complete working examples:
- Basic Example: Simple card reading and monitoring
- Advanced Example: Complex operations like block reading/writing
Run examples:
cd Examples
dotnet runThe library provides comprehensive error handling:
try
{
var uid = await nfcReader.GetCardUIDAsync();
if (uid != null)
{
Console.WriteLine($"Card UID: {uid}");
}
}
catch (InvalidOperationException ex)
{
Console.WriteLine("Reader not connected");
}
catch (Exception ex)
{
Console.WriteLine($"Unexpected error: {ex.Message}");
}The library supports structured logging via Microsoft.Extensions.Logging:
using var loggerFactory = LoggerFactory.Create(builder =>
{
builder.AddConsole();
builder.SetMinimumLevel(LogLevel.Debug);
});
var logger = loggerFactory.CreateLogger<Program>();
var nfcReader = new NFCReader(logger);- Fork the repository
- Create a feature branch
- Make your changes
- Add tests for new functionality
- Ensure all tests pass
- Submit a pull request
This project is licensed under the MIT License - see the LICENSE file for details.
If you're migrating from the old library, here are the key changes:
var reader = new NFCReader();
reader.Connect();
var uid = reader.GetCardUID();using var reader = new NFCReader();
await reader.ConnectAsync();
var uid = await reader.GetCardUIDAsync();- All methods are now async
- Proper resource disposal with
usingstatements - Event-driven card detection instead of polling
- Better error handling and logging
- Cross-platform compatibility
-
"No readers found"
- Ensure PC/SC service is running
- Check if NFC reader is properly connected
- Verify drivers are installed
-
"Connection failed"
- Reader may be in use by another application
- Check reader permissions
- Restart PC/SC service
-
"Card not responding"
- Ensure card is properly positioned
- Check if card is compatible
- Verify card is not damaged
Windows:
- Ensure Windows Smart Card service is running
- Check Device Manager for reader status
macOS:
- Install PCSC-Lite:
brew install pcsc-lite - Start service:
brew services start pcsc-lite
Linux:
- Install PCSC-Lite:
sudo apt-get install pcscd - Start service:
sudo systemctl start pcscd
For issues and questions:
- Check the Issues page
- Review the examples and tests
- Ensure your system meets the requirements
- Complete rewrite for modern .NET
- Cross-platform support
- Async/await support
- Event-driven architecture
- Comprehensive testing
- Better error handling and logging