# Conventions *Conventions* can be used to identify which types are messages, commands, and events, instead of using [marker interfaces](/nservicebus/messaging/messages-events-commands.md#identifying-messages-marker-interfaces). This can be done to avoid references to the NServiceBus assembly, referred to as *[unobtrusive mode](unobtrusive-mode.md)*. This is ideal for use in cross-platform environments. > [!NOTE] > For systems using NServiceBus version 8 or higher, it's preferable to use the marker interfaces in the [NServiceBus.MessageInterfaces package](https://www.nuget.org/packages/NServiceBus.MessageInterfaces) to build message assemblies that can be shared between different major versions of NServiceBus and different versions of .NET. See the details in the [sharing message assemblies sample](/samples/message-assembly-sharing/index.md). Currently, *conventions* exist to identify: - [Commands](/nservicebus/messaging/messages-events-commands.md) - [Events](/nservicebus/messaging/messages-events-commands.md) - [Messages](/nservicebus/messaging/messages-events-commands.md) - [Message Property Encryption](/nservicebus/security/property-encryption.md) - [Data Bus](/nservicebus/messaging/claimcheck/index.md) - [TimeToBeReceived](/nservicebus/messaging/discard-old-messages.md) Message types can be defined in a *Portable Class Library* (PCL) and shared across multiple platforms, even if the platform does not use NServiceBus for message processing. ```cs var conventions = endpointConfiguration.Conventions(); conventions.DefiningCommandsAs(type => type.Namespace == "MyNamespace.Messages.Commands"); conventions.DefiningEventsAs(type => type.Namespace == "MyNamespace.Messages.Events"); conventions.DefiningMessagesAs(type => type.Namespace == "MyNamespace.Messages"); conventions.DefiningClaimCheckPropertiesAs(property => property.Name.EndsWith("DataBus")); conventions.DefiningTimeToBeReceivedAs(type => type.Name.EndsWith("Expires") ? TimeSpan.FromSeconds(30) : TimeSpan.MaxValue); ``` > [!NOTE] > In .NET, the namespace is optional and can be null. If any conventions do partial string checks, for example using `EndsWith` or `StartsWith`, then a null check should be used. Include `.Namespace != null` at the start of the convention to avoid a null reference exception during type scanning. ## Using both default and custom conventions Defining a custom convention will overwrite the default convention. If both default and custom conventions are needed, the default conventions must be specified along with the custom conventions. ```cs var conventions = endpointConfiguration.Conventions(); conventions.DefiningCommandsAs(type => type.Namespace == "MyNamespace.Messages.Commands" || typeof(ICommand).IsAssignableFrom(type) ); conventions.DefiningEventsAs(type => type.Namespace == "MyNamespace.Messages.Events" || typeof(IEvent).IsAssignableFrom(type) ); conventions.DefiningMessagesAs(type => type.Namespace == "MyNamespace.Messages" || typeof(IMessage).IsAssignableFrom(type) ); conventions.DefiningClaimCheckPropertiesAs(property => property.Name.EndsWith("DataBus") || typeof(IClaimCheckProperty).IsAssignableFrom(property.PropertyType) && typeof(IClaimCheckProperty) != property.PropertyType ); conventions.DefiningTimeToBeReceivedAs(type => type.Name.EndsWith("Expires") ? TimeSpan.FromSeconds(30) : type.GetCustomAttribute(false)?.TimeToBeReceived ?? TimeSpan.MaxValue ); ``` ## Encapsulated conventions Messaging conventions can be encapsulated into a class. ```cs class MyNamespaceMessageConvention : IMessageConvention { public bool IsMessageType(Type type) => type.Namespace == "MyNamespace.Messages"; public bool IsCommandType(Type type) => type.Namespace == "MyNamespace.Messages.Commands"; public bool IsEventType(Type type) => type.Namespace == "MyNamespace.Messages.Events"; public string Name { get; } = "MyNamespace message convention"; } ``` These conventions can be added to the endpoint. ```cs endpointConfiguration.Conventions().Add(new MyNamespaceMessageConvention()); ``` Multiple encapsulated conventions can be applied to the same endpoint. A class will be considered a message, command, or event if any convention matches it. > [!NOTE] > Adding an instance of `IMessageConvention` does not override the default conventions. ## Attributes If attributes are preferred over marker interfaces, use [NServiceBus.AttributeConventions](https://github.com/mauroservienti/NServiceBus.AttributeConventions), a [community package](/nservicebus/community/index.md) that allows using attributes instead of interfaces.