You can customize all texts of exceptions raised by built-in contracts. This allows you to localize error messages into different languages.
Contracts use the ContractLocalizedTextProvider class to obtain the text of an error message. This class follows a simple chain of responsibility pattern where each provider has a reference to the next provider in the chain. When a message is queried, the provider either returns a message or passes control to the next provider in the chain.
Each message is identified by a string identifier and can refer to four basic arguments and additional arguments specific to a message type. For general information about message arguments see the remarks section of LocationContractAttribute. To find the identifier of a particular message and its additional arguments, see the remarks section of the contract classes in PostSharp.Patterns.Contracts.
Localizing a built-in error message
The following steps illustrate how to override an error message of a given contract:
Creating a localized text provider
Declare a class that derives from ContractLocalizedTextProvider and implement the chain constructor.
public class CzechContractLocalizedTextProvider : ContractLocalizedTextProvider { public CzechContractLocalizedTextProvider(ContractLocalizedTextProvider next) : base(next) { } }Implement the GetMessage(string) method. In the next code snippet, we show how to build a simple and efficient dictionary-based implementation.
public class CzechContractLocalizedTextProvider : ContractLocalizedTextProvider { private readonly Dictionary<string, string> messages = new Dictionary<string, string> { {RegularExpressionErrorMessage, "Hodnota {2} neodpovídá regulárnímu výrazu '{4}'."}, }; public CzechContractLocalizedTextProvider(ContractLocalizedTextProvider next) : base(next) { } public override string GetMessage( string messageId ) { if ( string.IsNullOrEmpty( messageId )) throw new ArgumentNullException(nameof(messageId)); string message; if ( this.messages.TryGetValue( messageId, out message ) ) { return message; } else { // Fall back to the default provider. return base.GetMessage( messageId ); } } }Note
If you need to support several languages, you can make your implementation of the GetMessage(string) method depend on the value of the CurrentCulture property. You can optionally store your error messages in a managed resource and use the ResourceManager class to access it and manage localization issues. The design of PostSharp Code Contracts is agnostic to these decisions.
At the beginning of the application, create a new instance of the provider and set the current provider as its successor.
public static void Main() { ContractServices.LocalizedTextProvider = new CzechContractLocalizedTextProvider(ContractServices.LocalizedTextProvider); // ... }
Localizing custom contracts
Once you have configured a text provider, you can use it to localize error messages of custom contracts. In the following procedure, we will localize the error message of the example contract described in Creating Custom Contracts.
Adding the message of a custom contract
Edit the code contract class (
NonZeroAttributein our case) to callContractServices.ExceptionFactory.CreateException()in the validation method(s), as shown in Customizing Contract Exceptions. Use a uniquemessageId(for example, "NonZeroErrorMessage") to identify the message text template.Edit your text provider class (
CzechContractLocalizedTextProviderin our case) and include the message for your custom contract:private readonly Dictionary<string, string> messages = new Dictionary<string, string> { {RegularExpressionErrorMessage, "Hodnota {2} neodpovídá regulárnímu výrazu '{4}'."}, {"NonZeroErrorMessage", "Hodnota {2} nesmí být 0."} };