One of the biggest mistakes architects can make when designing Enterprise Services is to assume that its sole purpose is to provide wrappers for existing unmanaged COM+ and MTS functionality. It’s a common assumption, given that the current Enterprise Services implementation provides little more than a managed interface to unmanaged COM+.

However, Microsoft views Enterprise Services quite differently. In its eyes, Enterprise Services is the replacement for COM+ and MTS. Going forward, Microsoft has two primary goals for new versions of the .NET Framework, starting with release 1.1 that’s due with Windows .NET Server 2003. First, all existing COM+ functionality will move to managed code. Second, all new distributed systems management functionality will be implemented in Enterprise Services in .NET. In fact, COM+ version 1.5 (released with Windows XP) will likely be the last version of COM+ available as an unmanaged release.

What is Enterprise Services?
Given Microsoft’s emphasis on Enterprise Services as its distributed systems development platform, you need to understand exactly what services Microsoft is talking about. Enterprise Services supports resource management in a distributed environment. This functionality includes support for distributed transactions, role-based security and packaging of objects, object pooling, just-in-time-activation (JITA), queued components, and loosely coupled events. When used together, these functions give architects the tools to implement a complete server application process model.

One of the most confusing aspects of Enterprise Services is when to use them. If your existing systems use COM+ extensively, you’ll naturally want to use Enterprise Services when porting your applications to .NET. But if you don’t use COM+ today, how do you get started and what’s the benefit?

Implementing transaction support
To understand how you can get started with Enterprise Services, let’s look at how you implement transaction support in three different scenarios: traditional distributed applications, Web services, and ASP.NET applications. It’s important to differentiate between how developers handle transactions in the COM+ world vs. .NET. In COM+, developers manually start a transaction and then check conditions to determine whether the transaction should be committed or aborted. But .NET lets you handle transaction commits and aborts automatically by using declarations exposed through attributes. In other words, you can think of distributed transactions as automatic or declarative transactions in .NET. (Developers still have the option of coding commits and aborts manually if they need that granular level of control.)

Traditional distributed applications
For a traditional distributed application, the developer needs to create a server object and then code the client to call the server object. Here’s a simple implementation of a server object implemented in C#:
using System;
using System.EnterpriseServices;
[assembly : ApplicationName(“TxDemo”)]
public class Account : ServicedComponent {
public void Credit() {
// do some work
} }

We should note three important items from this sample. First, the statement, using System.EnterpriseServices; gives you access to attributes in the Enterprise Services namespace. Second, the Account class inherits from the existing ServicedComponent class, where it gets its ability to be managed by EnterpriseServices. Finally, the Transaction and AutoComplete attributes make objects instantiated from this class transactional. The AutoComplete attribute tells EnterpriseServices to commit the work done in the Credit function unless an error occurs, in which case it should abort. You still can catch exceptions and swallow them (i.e., not Throw them up the call stack) with AutoComplete committing the transaction.

Here’s the code required to use the Credit object from a client application:
public Class AccountClient {
private void Transactions_Click() {
Account account = New Account();
} }

Notice that the client has no idea that the server object uses transaction management.

Web Services
If your users need to consume resources managed by Enterprise Services but access them through a Web Services interface, you can expose those resources using parameters on the WebMethod attribute declaration. For example, the code below allows the WebMethod DeleteAuthor to create a new transaction before attempting to delete the author passed in by the user of the Web service:
public int DeleteAuthor(string lastName) {

Any other business objects called by this WebMethod automatically inherit its transaction context as long as they are marked to either Support or Require a transaction.

ASP.NET applications
Using transactions from ASP Pages is simple, as well. You add a page-level directive like this:
<%@ Page Transaction=”Required” %>

The Required setting allows this page to initiate a new transaction if it’s not already participating in an existing one. Any components called by this page will participate in the same transaction context.

What’s the benefit of Enterprise Services?
Before we look at the benefit of Enterprise Services, let’s first consider the widely discussed downside: performance. It’s true that calling serviced components is slower than calling other objects. This is because creating context and crossing context boundaries imposes overhead on your applications. But calling serviced components hosted in library applications (these run in-process with the application) is nearly as fast as calling nonserviced components. Server applications have a higher call time due to crossing process or machine boundaries. You determine whether components run as library or server applications when you install them in COM+.

But here’s the real issue: In most real-world applications, the performance cost of the infrastructure required to support Enterprise Services is minimal compared to the cost of the actual work that the component does. Moreover, if you didn’t use the features provided by serviced components, your code will likely have to do additional work to get the same functionality.

So when should you use serviced components? In general, if your application architecture can benefit from the services (like guaranteed transactions) provided by Enterprise Services, serviced components are worth the performance cost. You should also consider the ease of development and future expansion benefits of developing with serviced components. Development is simpler with serviced components. If you use a SqlTransaction object or OleDbTransaction object to manage transactions, you’ll have to manage the transaction yourself. With Enterprise Services, you simply add a Transaction attribute to your object(s). Enterprise Services ensures that transactions managed between multiple objects happen logically and consistently. For example, you won’t have to add any special logic to determine whether an object is the root of a transaction.

Future expansion is easier to accomplish if you code systems using serviced components from the start. Suppose you create an order management system that includes inventory tables managed as part of the overall order transaction. What if, in the future, the inventory tables move to a separate database? What if the inventory object is moved to a remote server? What if one of the objects wants to dispatch to a transactional message queue? If you built the system with manual transaction management, you’ll have to rewrite it in order to make it work in a distributed environment. Had you built the system using Enterprise Services, you could make these deployment decisions without requiring changes to the underlying application.

It will take time to learn how to implement serviced components correctly. And you may not need to use them for many of your smaller applications. But employing their functionality correctly for distributed applications will pay off in the long term because they allow you to make deployment decisions without regard for design decisions you made during development.