You can implement custom business logic for validating Modbus requests by assigning a method to the RequestValidator property of a ModbusTcpServer (or an RTU server).
Key behaviors:
- The validator function is called every time a client sends a request.
- It complements rather than replaces default server checks. The server will still perform its own validation for absolute register limits and unknown function codes.
- The validator must return a
ModbusExceptionCode. Returning ModbusExceptionCode.OK allows the request to proceed, while other codes will trigger a Modbus exception response to the client. - The validator receives
RequestValidatorArgs, which provides access to the Address, FunctionCode, and other request details.
var server = new ModbusTcpServer()
{
RequestValidator = this.ModbusValidator
};
private ModbusExceptionCode ModbusValidator(RequestValidatorArgs args)
{
// Example: check if address is within valid holding register limits
var holdingLimits = args.Address >= 50 && args.Address < 90 ||
args.Address >= 2000 && args.Address < 2100;
// Example: check if address is within valid input register limits
var inputLimits = args.Address >= 1000 && args.Address < 2000;
return (args.FunctionCode, holdingLimits, inputLimits) switch
{
// holding registers
(ModbusFunctionCode.ReadHoldingRegisters, true, _) => ModbusExceptionCode.OK,
(ModbusFunctionCode.ReadWriteMultipleRegisters, true, _) => ModbusExceptionCode.OK,
(ModbusFunctionCode.WriteMultipleRegisters, true, _) => ModbusExceptionCode.OK,
(ModbusFunctionCode.WriteSingleRegister, true, _) => ModbusExceptionCode.OK,
(ModbusFunctionCode.ReadHoldingRegisters, false, _) => ModbusExceptionCode.IllegalDataAddress,
(ModbusFunctionCode.ReadWriteMultipleRegisters, false, _) => ModbusExceptionCode.IllegalDataAddress,
(ModbusFunctionCode.WriteMultipleRegisters, false, _) => ModbusExceptionCode.IllegalDataAddress,
(ModbusFunctionCode.WriteSingleRegister, false, _) => ModbusExceptionCode.IllegalDataAddress,
// input registers
(ModbusFunctionCode.ReadInputRegisters, _, true) => ModbusExceptionCode.OK,
(ModbusFunctionCode.ReadInputRegisters, _, false) => ModbusExceptionCode.IllegalDataAddress,
// deny other function codes
_ => ModbusExceptionCode.IllegalFunction
};
}