# Unit of Work ## Using a transaction scope If a business transaction spans multiple handlers, there is always a risk of partial updates, since one handler might succeed in updating the data while others don't. To avoid this, it is possible to use a unit of work that wraps all handlers in a `TransactionScope` and ensures no partial updates. Use the following code to enable a wrapping scope: ```cs var unitOfWork = endpointConfiguration.UnitOfWork(); unitOfWork.WrapHandlersInATransactionScope(); ``` > [!NOTE] > This requires the selected [persistence](/persistence/index.md) to support enlisting in transaction scopes. > [!WARNING] > This might escalate to a distributed transaction if data across different databases is updated. > [!WARNING] > This API must not be used in combination with transports running in *transaction scope* mode. Wrapping handlers in a `TransactionScope` in such a situation throws an exception. ### Controlling transaction scope options The following options for transaction scopes used to wrap all handlers can be configured. ### Isolation level NServiceBus will by default use the `ReadCommitted` [isolation level](https://msdn.microsoft.com/en-us/library/system.transactions.isolationlevel). Change the isolation level using ```cs var unitOfWork = endpointConfiguration.UnitOfWork(); unitOfWork.WrapHandlersInATransactionScope( isolationLevel: IsolationLevel.RepeatableRead); ``` ### Transaction timeout NServiceBus will use the [default transaction timeout](https://msdn.microsoft.com/en-us/library/system.transactions.transactionmanager.defaulttimeout) of the machine on which the endpoint runs. Change the transaction timeout using ```cs var unitOfWork = endpointConfiguration.UnitOfWork(); unitOfWork.WrapHandlersInATransactionScope( timeout: TimeSpan.FromSeconds(30)); ``` Or via .config file using a [example DefaultSettingsSection](https://msdn.microsoft.com/en-us/library/system.transactions.configuration.defaultsettingssection.aspx#Anchor_5). ## Implementing custom unit of work A unit of work allows for shared code, that wraps handlers, to be reused in a way that doesn't pollute the individual handler code. For example, committing NHibernate transactions, or calling `SaveChanges` on a RavenDB session. ### IManageUnitsOfWork To create a unit of work, implement the `IManageUnitsOfWork` interface. ```cs public class MyUnitOfWork : IManageUnitsOfWork { public Task Begin() { // Do custom work here return Task.CompletedTask; } public Task End(Exception ex = null) { // Do custom work here return Task.CompletedTask; } } ``` The semantics are that `Begin()` is called when the transport messages enters the pipeline. A transport message can consist of multiple application messages. This allows any setup that is required. The `End()` method is called when the processing is complete. If there is an exception, it is passed into the method. This gives a way to perform different actions depending on the outcome of the message(s). partial: access-to-context partial: imanageunitsofwork-outbox partial: nulltask ### Registering custom unit of work After implementing an `IManageUnitsOfWork`, it needs to be registered: ```cs endpointConfiguration.RegisterComponents( registration: components => { components.ConfigureComponent(DependencyLifecycle.InstancePerUnitOfWork); }); ```