Making Business-to-business Calls
Sometimes you need to implement distributed transactions involving different business layer methods in addition to DAL methods. If all the operations execute inside different transactions (where the business layer code is set to the
RequiresNewTransaction COM+ pattern), everything works according to the sequence already shown. However, if you need to execute multiple operations inside the same transaction's context (the
RequiresTransaction pattern), you must provide two overloads for the business layer methods involved. The first accepts a DistributedTransaction object as an input parameter; the second does not. Otherwise, all the other parameters are identical. In this scenario, the overload that requires the DistributedTransaction parameter is a "secondary" method that implements a local business operation, acting as a server for the "primary" methods that start transactions and define business operations at a higher level.
The overload that doesn't take a DistributedTransaction looks like this:
' -- First overload without transaction
Public Sub DoSomething (ByVal input as Object)
' [...] Validates parameters
' -- Defines transactional context for business operations
Dim tr As DistribuitedTransaction
Try
' -- starts transaction
tr = New Transaction(_connstring)
' - Calls business method that requires transaction
DoSomething (input, tr)
' [...] If required, can also call other business or
' data methods passing tr as context
' -- commits transaction
tr.Commit()
Catch ex As Exception
' -- Rolls back Transaction
tr.Abort()
' [...] Logs error
Throw ' some user defined error...
Finally
' -- Releases transaction
tr.Dispose()
End Try
End Sub
Here's the overload that accepts a DistributedTransaction.
' -- Second overload with transaction
Friend Sub DoSomething (ByVal input as Object,
ByVal tr As Transaction)
'— [...] checks parameter
Try
Dim myData As New DAL
myData.DoSomething (input, tr)
Catch ex As Exception
' -- disable transaction's commit
tr.DisableCommit()
' [...] Logs error
Throw
End Try
End Sub
In C#:
// First overload without transaction
public void DoSomething(object input) {
// [...] Validates parameters
// Defines transactional context for business operations
DistribuitedTransaction tr;
try {
// starts transaction
tr = new Transaction(_connstring);
// Calls business method that requires transaction
DoSomething(input, tr);
// [...] If required, can also call other business or
// data methods passing tr as context
// commits transaction
tr.Commit();
}
catch (Exception ex) {
// Rolls back Transaction
tr.Abort();
// [...] Logs error
throw;
}
finally {
// Releases transaction
tr.Dispose();
}
}
// Second overload with transaction
internal void DoSomething(object input, Transaction tr) {
// [...] checks parameter
try {
DAL myData = new DAL();
myData.DoSomething(input, tr);
}
catch (Exception ex) {
// disable transaction's commit
tr.DisableCommit();
throw;
}
}
The first method creates the transaction and calls the overload that requires it as input. This method works exactly as described earlier for simpler scenarios, except that it uses the passed-in DistributedTransaction object instead of creating a new one. Note its error handler, which acts like error handlers typically found in DAL methods. In other words, it calls
DisableCommit rather than rolling back the transaction, because this particular business layer method has a secondary role, just as DAL methods usually do. It's usually better to define such support methods as
Private or
Friend, so they can't be exposed outside the project; however, sometimes the assembly structure will require you to distribute the business operation in such a way that you must define all overloads as
Public. In this particular case, the
Façade layer's components expose and map only business methods that don't require transactions.
With this last structure in place, you have in fact replicated the
NewTransaction and
RequiresNewTransaction COM+ patterns used in a declarative way in VB6 and other COM-based languages. You obviously still need code to implement the various layers, but now you can write that code in a clear linear fashion that's much simpler than using only the ADO.NET base objects.