﻿# Unit of Work

<!-- Version variant: core_9; default: [/nservicebus/pipeline/unit-of-work.md](/nservicebus/pipeline/unit-of-work.md) -->


## 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:

<!-- snippet: UnitOfWorkWrapHandlersInATransactionScope -->

```cs
var unitOfWork = endpointConfiguration.UnitOfWork();
unitOfWork.WrapHandlersInATransactionScope();
```

<!-- endsnippet -->

> [!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

<!-- snippet: UnitOfWorkCustomTransactionIsolationLevel -->

```cs
var unitOfWork = endpointConfiguration.UnitOfWork();
unitOfWork.WrapHandlersInATransactionScope(
    isolationLevel: IsolationLevel.RepeatableRead);
```

<!-- endsnippet -->

### 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

<!-- snippet: UnitOfWorkCustomTransactionTimeout -->

```cs
var unitOfWork = endpointConfiguration.UnitOfWork();
unitOfWork.WrapHandlersInATransactionScope(
    timeout: TimeSpan.FromSeconds(30));
```

<!-- endsnippet -->

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

In scenarios, when custom unit of work is needed (e.g. to commit NHibernate transactions, or call `SaveChanges` on a RavenDB session without polluting handers logic) it can be implemented using a [dedicated pipeline behavior](/samples/pipeline/unit-of-work/index.md).
