Designing Components for an Application or Service


Detailed Summary

Component Types

Every software solution, regardless of its specific business needs, uses similar kinds of components. For example, most if not all distributed applications need to use a data access component,  Identifying these kinds of common components found in distributed applications will help you build a blueprint for an application or service design. The following figure shows common component types found in most distributed applications:

These components types are described below:

  1. UI Components
    User Interfaces are implemented using Windows Forms, ASP.NET, controls, or any other technology uses to format/render data for users and to acquire/validate data coming from users.
  2. UI Process Components
    In many cases, a user's interaction with the system follows a predictable process. For example, to search for an item you may need to specify some sort of product/item ID, apply an appropriate filter, and then indicate how output should be formatted. Rather than hard-coding this logic within the UI elements, you can use a UI process component to help synchronize and orchestrate these user actions. UI Process Components (or UI Managers as I prefer to call them) ensure that the process flow and its state management are encapsulated within a component that can be potentially reused by multiple UIs. In the example above, a SearchManager is the appropriate UI process component. 
  3. Service Interfaces
    Service interfaces are often referred to as business facades. Service interfaces are used to expose business logic as a service.
  4. Business Workflows
    Business workflows define and coordinate long-running, multi-step business processes. Many business processes involve multiple steps that must be orchestrated and performed in the correct order. For example, committing an order may involve multiple steps (verifying inventory, calculating total cost, authorizing payment, arranging delivery) and can take an indeterminate amount of time to complete. Therefore, tasks involved in committing an order and the data required to complete them would have to be managed.
  5. Business Components
    Business components implement the business logic of the application. Business Workflows use business components. From the previous example given in Business Workflows, the tasks involved in committing an order would each be implemented as a business component - you would have a component to verify inventory, another component to calculate total cost, and so on.
  6. Business Entities
    Business entities are internal data structures that represent real-world entities that the application has to work with such as a product or an order. Business entities are often implemented as DataSets, DataReaders, or XML streams so that they can be passed between data access components and UI components.
  7. Data Access Logic
    Data Access components are used to abstract data access in a separate layer. Doing so centralizes data access functionality and makes it easy to maintain. 
  8. Service Agents
    Service agents can be considered as adapters that convert the varying interfaces of different services into compatible interface with the client application. Service agents can also provide additional services such as mapping between data formats required by the application and the service. For example, if the credit card authorization service is on a Unix machine, you could use a service agent to manage communication via TCP/IP and translate data formats back and forth between Unix and the .NET application. 

The remaining components, security, operations, and communications involve components used to perform exception management, caching, authorizations, and other tasks required to communicate with other applications and service. and will be discussed in detail in Security, Operational Management, and Communications Policies.

The following table roughly illustrates how the given component types (process components, data access logic, etc) map to certain design patterns:

Component Type Related Design Pattern
UI Component Presentation Layer
View Layer
Client Layer
UI Process Component Application Controller Pattern
Mediator Pattern
Application Model Layer
Service Interfaces Remote Facade Pattern
Business Workflows Domain Layer
Business Components Domain Layer
Transaction Script Pattern
Business Entities Data Transfer Object
Domain Model
Data Access Logic Components Data Source Layer
Infrastructure Layer
Integration Layer
Service Agents Data Source Layer
Infrastructure Layer
Integration Layer

Design Recommendation for Applications and Services

Consider the following recommendations when designing applications and services:

Designing Presentation Layers

Definition: The presentation layer consists of all components required to enable user interaction with the system.

The most simple presentation layer contains UI components such as Windows Forms or ASP.NET. For more complex user interactions, you can design UI process components to orchestrate UI elements and control user interactions. UI process components are useful when user interactions follow a specific pattern (just like a wizard used to accomplish a task).

Designing presentation layers contains two broad topics:

Designing UI Components

UI Components, which manage interactions with the user, may be implemented in different ways. For example, you can have Web-based UI, Windows-Forms UI, voice rendering, document-based programs, mobile client applications, and so on. 

When accepting user input, UI components::

When rendering output, UI components:

While the list is not exhaustive, it lists some of the more common requirements that all UI components should provide. UI design requirements for more specific types of UI are shown below:

Windows Desktop UI

Windows UI is typically used when you need to provide rich user interaction and/or offline (disconnected) capabilities, or even integration with the UI of other applications. Windows UI can take advantage of a wide range of state management and persistence options and can access local processing power.

There are three main families of Windows standalone user interfaces:

Consider the following design recommendations when creating Windows Form-based applications:

private void grid_BeforeCellUpdate( object sender, System.EventArgs e)
    VerifyUserInput( grid.GetCurrentCell );

Internet Browser UI

Consider the following design recommendations when creating ASP.NET user interfaces:

Document-based UI

In some cases rather than building a custom Windows Forms application to facilitate user interaction, it might me more appropriate to allow user to interact with the system through documents created by common tools such Microsoft Office. Documents can be considered as a metaphor for working with data, and users may benefit from viewing/entering data in using documents from tools they often use.

Consider document-based UI in the following cases:

In general, there are two common ways to integrate documents into applications, working with the documents from the inside and working with the documents from the outside:

Working with Documents from the Outside

In this scenario you treat the document as an entity. The document itself has no specific awareness of the application. In this design model, the UI will perform the following functions:

Working with Documents from the Inside

In this scenario you embed application logic into the document itself to provide the user with an integrated experience within the document. In this design model, the UI will perform the following functions:

Accessing Data Access Components from the UI

UI may need to render data that is readily available as queries exposed by data access components. Calling data access components from the UI may seem to contradict the layering concept, however, it can be used to adopt the perspective of your application as one homogenous service. In general, you should allow UI to directly invoke data access components when:

Designing User Process Components

Note: Implementing UI with user process components is not trivial. Before committing to this approach, evaluate whether or not your application requires this level of abstraction and orchestration.

As noted in the definition of User Process Components,a user's interaction with the system may follow a predictable process. Rather than hard-coding this logic within the UI elements, you can use a UI process component to help synchronize and orchestrate these user actions. UI Process Components - or UI Managers as I prefer to call them- ensure that the process flow and its state management are encapsulated within a component that can be potentially reused by multiple UIs. For example, a SearchManager is an appropriate UI process component to synchronize and orchestrate (i.e., manage) product look-ups. Therefore, partitioning user interaction flow from the activities of rendering data and gathering data from the user can increase the application's maintainability and provide a clean design to which you can easily add seemingly complex features. Otherwise, an unstructured approach to implementing user interface logic may result in undesirable situations where if you need to add a specific UI to a given device (i.e., Windows Forms, or ASP.NET), you may need to redesign control logic and data flow.

User process components are typically implemented as .NET classes that expose methods that can be called from the UI, with each method encapsulating logic to perform a specific action in the user process. As expected then, the UI creates an instance of a user process component and uses it to transition through the various steps of the process.

Designing a user process component to be used from multiple UIs (Windows Forms, ASP.NET, etc.), results in a more complex implementation to avoid device-specific issues. Nonetheless, it can help distribute the UI development work between multiple teams, each using the same UI process component. You should also design process components with globalization in mind to allow for localization to be implemented in the user interface. For example, try to use culture-neutral formats and Unicode strings to make easier for the localized UI to call the user process component.

The following code snippet show a typical user process component for product look-up:

public class SearchManager
    /* Data members */

    /* Public interface */
    public void SetProduct( Product obProd )
    { ... }

    public void SetFilter( Filter obFilter )
    { ... }

    public ProductsCollection Search()
    { ... }

    public void ClearProducts()
    { ... }

The following topics are covered:

Advantages of user process components

Separating user interaction functionality into user interface and user process components provides the following advantages:

Design of user process components

The following sub-sections explain the steps involved in designing user process components:

User process identification

Before you can design a user process, you must first identify it. When reading the following points, it can be helpful to have the 'saving a shopping cart' user process in-mind:

User process functionality

User process components do the following:

User process design

A user process should be designed to expose the following interfaces:

These interfaces are explained below:

  1. Actions: These are methods that typically trigger some change in the state of the user process. Actions are implemented as methods such as PlaceOrder, ProcessPaymentDetails, and so on.
  2. State: These are set/get properties that allow access to business-specific and business-agnostic state of the user process.
  3. Events: Events that are fired on changes in the business-specific and business-agnostic state of the user process.
  4. Control: Control functions to start/pause/restart/stop a particular user process. Control methods are often used to load required data for UI.

Designing Business Layers

Business functionality is the core of the application. An application performs a business process that consists of one or more tasks. In the simplest case, each task can be represented as a single method in a component, and this method can be called either synchronously or asynchronously. For example, you might have an application whose business process is selling books. Selling books obviously consists of many tasks such as capturing customer's order, verifying payment details, arranging delivery, and so on. A more complex business process has multiple tasks, but each task may require multiple steps with long running transactions. For these complex business processes, the application needs some way of orchestrating business tasks and storing state until the process is completed.

You can design the logic in the business layers to be used directly by the presentation components, or to be encapsulated as a service and be called through a service interface. Your business components may also make requests of external services, in which case you may need to implement service agents to manage conversation with those external services. The following figure and subsequent sections refer to individual components of the business layer:


Business Components and Business Workflows

One of the first decisions in designing a business layer is to decide if a set of business components will be sufficient or if you need to orchestrate the business process performed by these business components.

When to implement the business process using a set of business component:

When to implement the business process using business components and workflows:

For example, the business process of placing an order involves many steps and these steps must be performed in a specific sequence (collecting order item, calculating total cost, authorizing payment, arranging delivery, and so on). The appropriate design for this business process is to create business components encapsulating each step and then to orchestrate these steps using a business workflow.

Designing Business Components

Business components implement business rules and accept/return simple and complex data. Business components should expose functionality that is agnostic to data stores (databases, files, storage, etc.) and services needed to perform the work.

If a business process invokes other business processes in the context of an atomic transaction, all the invoked business processes must ensure their operations participate in the existing transaction, so that their operations can roll-back if the calling business logic aborts. This implies that is should be safe to retry an atomic transactions if it fails without worrying about making data inconsistent. Think of a transaction boundary as a retry boundary.  Microsoft offers several technologies for managing transactions - Distributed Transaction Coordinator (DTC),  COM Transaction Integrator (COMTI), and Host Integration Server.

If you cannot implement atomic transactions, you must provide compensating methods and processes. Note that a compensating action does not necessarily roll-back application data to the previous state, but rather restored the business data to a consistent state. For example, when canceling an order, you have to restore the product quantity for each ordered product, but you may also impose a fee for order cancellation. 

The following list summarizes recommendation for designing business components:

Implementing Business Components

The following list summarizes recommendation for implementing business components. Business components:

The following figure shows a typical business component interacting with components from surrounding layers, and with components from the same layer:

Patterns for Business Components

There are many commonly used patterns that can be applies when it comes to implementing business components:

Pipeline Pattern

A pipeline defines a collection of steps that execute in sequence to fulfill a business process. Each step may involve reading or writing data to confirm the pipeline state, and may or may not access an external service. When executing an asynchronous service as part of a step, the pipeline can wait until a response is returned or process to the next step in the pipeline if a response is not required in order to continue processing. The pipeline pattern can be used when:

The advantages of this pattern is that it is simplifies the actions of a business component into small and well-known steps, enforces sequential processing, and makes it easy to wrap in an atomic transaction. Disadvantages include inability to handle well conditional constructs, loops and other flow logic.

Event Pattern

From a business component point of view, the event pattern is semantically the same as that in Windows Forms. Whereas UI elements in a Windows Forms application fire UI events (OnMouseDown) in response to user actions and event handlers handle those events, so are business events fired under particular business conditions and business components are written to handle those events. The event pattern is used when:

The advantages of this pattern is that maintainability is improved by keeping unrelated business processes independent, encourages parallel processing, and is agnostic to whether implementations run synchronously or asynchronously because no response is required. Disadvantages include factors such as inability to build complex responses for the business function, and inability to use status/data of another component.

Business Workflows

The following diagram shows how an orchestrated business process interacts with other components from with the same layer and from different layers:

Note the following points:

When designing business workflows you must consider long response times or no responses at all.

Service Interfaces

If you are exposing business functionality as a service, you need to provide clients of this business process with an entry point by creating a service interface. A service interface is typically implemented as a facade that handles mapping and transformation services, and enforces a process and a policy for communication. A service interface implements a set of methods that can be called individually or in a specific sequence to form a conversation that implements a business process. For example, a service interface for credit card payment may expose two methods - AuthorizeCard and ProcessPayment - and these two methods need to be called in sequence to actually accept payment from the user. From an implementation perspective, it is important to note that a service interface is actually another component (a C# class rather than an interface.)

Consider the following when designing service interfaces:

Using Business Facades with Service Interfaces

If you are planning on building a system that may be invoked through different mechanisms, then you should add a facade between the business logic and the service interface. For example, if you choose to build a Web Service, then most of the service interface logic will be in the Web Service itself (.asmx files). This facade provides extra maintainability because it can isolate changes - say in the communication mechanism - from the implementation of the business logic. The service interface then only deals with the specifics of the communication mechanism or channel (for example, examining SOAP headers for context information). The following figure illustrates:

In the above figure, an ASP.NET application running IIS receives an HTTP message and then invokes Service Interface 1 which inspects some SOAP header values and sets the correct principal object based on the authentication of the Web Service. Service Interface 1 then invokes the Business Facade component to validate, authorize, and audit the call. The facade then invokes the business component to perform the actual business work. At a later stage in the application lifecycle, it was determined that business components should also be available via MSMQ. A custom MSMQ listener is used to pick up messages and then invokes Service Interface 2 to extract some data off the message and set the correct principal object on the thread based on the message signature. Then the facade is used to invoke the business component as usual. The main point here is that by factoring the code of the business facade outside of the service interface, the application was able to add a communication mechanism without having to change the business component.

Transaction Management in Service Interfaces

The service interface will need to deal with channels that do not provide transactional capabilities (XML Web Service) and channels that do provide transactional capabilities (Message Queuing). It is very important that transaction boundaries can be designed so that operations can be retried in an error. To do so, make sure that all your resources are transactions and that root components require transactions while all other sub components require/support transactions:

Business Entities

Business entities exhibit the following behavior:

 The following business entity topics are further discussed:

Representing Business Entities

When passing data around from one layer to another, or even within different components in the business layer, you can do so in many formats. These formats vary from data-centric like XML to more object-oriented like a Typed DataSet. Common formats for passing data in .NET applications are:

Generally, it is recommended that data-centric formats like DataSets be used to pass data between tiers. DataSets can then be used to hydrate custom business entities if you want to work with data in an object-oriented approach. In many cases, it will also be simpler to work with business data directly from the DataSet.

Guidelines Advantages Disadvantages


  • Decide whether the XML document should contain a single business entity or a collection of business entities.
  • Use a namespace to uniquely identify the document.
  • Retrieve business entities in XML using SQL Server FOR XML clause, or a DataSet that is tranformed into XML, or by building the business entity XML from scratch
  • Standards support.
  • Flexibility as XML can represent hierarchies and collections
  • Interoperability with external partners and services


  • Type fidelity is not preserved, but you can use XSD for simple data typing.
  • Parsing XML (manually or via XSD) is slow.
  • Cannot automatically bind XML data to UI. You will need to write an XSLT transformation to transform the data into a .NET bindable type.
  • Cannot automatically sort XML. You may need to use XSLT or transform the data into a sortable .NET type like a DataView .
  • Very flexible.
  • Supports serialization.
  • Supports data binding to any UI element.
  • Interchangeable with XML
  • Availability of metadata.
  • Supports optimistic concurrency.
  • High instantiation and marshalling costs.
  • Do not have the option of hiding information through private fields.
Custom Business Entity Component     
  • Contains private fields to cache the entity's data locally.
  • Contains public properties to access the state of the entity.
  • Contains methods to perform localized processing.
  • Contains events to signal changes in the entity's internal state.
  • Code readability via typed methods and properties.
  • Can contain methods to encapsulate simple business rules such as IncreasePriceNPercent(int n).
  • Can perform simple validation tests.
  • Can hide information via private fields.
  • A custom business entity represents a single business entity. Calling application must use a collection to hold multiple business entities.
  • You must implement serialization
  • You must implement your own mechanism for representing hierarchies and relationship of data in a business entity component.
  • You must implement IComparable to allow entity components to be held in a sortable container.
  • You must deploy assembly containing business entity to all physical tiers.
  • If database schema is modified, the custom business entity needs to be modified and redeployed. 

In most cases you should work with data directly using XML documents or data structures provided by ADO.NET - DataSet, DataTable, etc.  This allows you to pass structured data between the layers of your application without having to write any custom code.  Business entities are custom components used to represent data and they are considered as part of the business layer. Business entities can be consumed by other business components or by presentation components. 

Business Entity Consumers

So who consumes business entities? Consumers include:

 Business Entity Interface Design

You only need to write custom business entity components if:

Business entity components must expose the following functionality:

Designing Business Entities

Consider the following recommendation when designing business entities:

Business Entity Example

The following represents a sample code of a business entity component called CustomerBusinessEntity that also exposes events as its state changes:

// Define a common event for all business entities
public class EntityEventArgs : EventArgs
    // Define event class members, like datetime, business entity type name
    // (obtained via reflection) and others
public delegate void EntityEventHandler (object sender, EntityEventArgs args);

/* A data access logic component called CustomerDALC will create the business entity and populate all its fields. */
public class CustomerBusinessEntity
    /* Events fired by this class */
    public event EntityEventHandler BeforeChange;
    public event EntityEventHandler AfterChange;

    /* Data members - private fields to hold state of the business entity */
    private string     m_strFirstName   = "";
    private string     m_strLastName    = "";
    private string     m_strAddress     = "";
    private DateTime   m_dtDOB;
    private DataTable  m_dtCurrentOrders;

    /* Public properties to get/set state of object */
public string FirtName
        get { return m_strFirstName; }
            BeforeChanges( this, new EntityEvnetArgs();
            m_strFirstName = (string)value;
            AfterChanges( this, new EntityEvnetArgs();

    public string LastName
        get { return m_strLastName; }
            BeforeChanges( this, new EntityEvnetArgs();
            m_strLastName = (string)value; 
            AfterChanges( this, new EntityEvnetArgs();

    public string Address
        get { return m_strAddress; }
            BeforeChanges( this, new EntityEvnetArgs();
            m_strAddress = (string)value;
            AfterChanges( this, new EntityEvnetArgs();


    public DateTime DOB
        get { return m_dtDOB; }
            BeforeChanges( this, new EntityEvnetArgs();
            m_dtDOB = (DateTime)value;
            AfterChanges( this, new EntityEvnetArgs();

    public DataTable CurrentOrders
        get { return m_dtCurrentOrders; }
            BeforeChanges( this, new EntityEvnetArgs();
            m_dtCurrentOrders = (DataTable)value;
            AfterChanges( this, new EntityEvnetArgs();

    /* Public methods to perform some localized processing */
public bool IsCustomerInAgeGroup( int nAgeGroup )
        // Determine age group based on customer's DOB

Exception Handling in Business Entities

Business entity components should propagate exceptions to their direct callers. Business entity components may also raise exceptions if they are performing any validations or if, for example, the caller supplies missing data. The following example illustrates:

public class CustomerEntity
    public void Update( string strFirstName, string strLastName )
            // Check that names are valid
            if (strFirstName == null) || (strLastName == null)
                throw new InvalidArgumentException ("Customer names are not valid" );

            if (strFirstName.Length == 0) || (strLastName.Length == 0)
                throw new InvalidArgumentException ("Customer names are empty" );

            // Call customer data access logic component to update customer

        catch( Exception ex )
            throw;        // Propagate exception to caller

Designing Data Layers

The following sections discuss the choice of data stores, design of data access components, and choices available for representing data

Data Stores

Common types of data stores include:

Data Access Logic Components

Data Access Logic Components abstract the semantics of the underlying data store (i.e., SQL Server) and the underlying data access technology (i.e., ADO.NET) and provide a simple programmatic interface for retrieving and operating on data. They are not to be confused with Data Access Helper Components which centralize generic data access functionality.

Data access logic components usually implement a stateless design pattern that separates the business processing from data access logic. Each data access logic component typically provides CRUD operations (Create, Read, Update, and Delete) relating to a specific business entity. They also include paging functionality when retrieving large records. When an application contains multiple data access logic components, it becomes important to centralize data access logic in a data access helper component that manages database connections, transactions, command execution, and so on.

The difference between data access logic component and data access helper components is that the former provides logic to access specific business data, while the latter centralizes data access API (i.e., ADO.NET) and data connection configuration. Note: See the Data Access Application Block provided by Microsoft, This block can be used as a generic data helper component.

The following figure shows the relation between data access logic components and data access helper components:

The following code show a partial skeletal outline of a data access logic component for accessing Order data:

public class ProductData
    // Constructors
    public ProductData                        { // Acquire connection string from a secure location }

    // Public interface
    public DataSet GetProducts()              { // Acquire all products }
    public DataRow GetProduct( long lID }     { // Acquire a specific products }
    public UpdataProduct( DataRow drProduct ) { // Update a specific product in the database }

The following sections provide more details on data access logic components:

Data access logic component functionality

Data access logic components should have the following functionality:

Data access logic components should not have the following functionality:

To support a wide range of business processes and applications, you can pass and return data to/fromData Access Logic Components in several different formats - arrays, XML, DataSets or custom business entity component.

Mapping Relational Data to Business Entities

One of the first steps in writing business entities is to decide how to map tables to business entities. For example, typical operations in a hypothetical retails would be to get/update information about a customer (including address), get a list of orders for a customer, get/update information about a product and so on. To fulfill these requirements, you can come up with three logical business entities - Customer, Product, and Order. For each business entity, a separate Data Access Logic Component (DALC) will be defined as follows:

To map relational data to business entities, observe the following guidelines:

Data access logic component interface design

Data access logic component often expose their functionality to the following consumers:

Data access logic component often expose the following functionality to their consumers:

Data access logic component design

When designing data access logic components, consider the following design recommendations:

Data Access Logic Component Example

The following represents a sample code of a data access logic component called CustomerDALC for the CustomerBusinessEntity class shown previously:

public class CustomerDALC
    /* Data members */
    private string m_strConnectionString = "";

    /* Constructors */
    public CustomerDALC()
        // Acquire the connection string from a secure location

    /* Data access methods */
    public CustomerBusinessEntity GetCustomer( int nID )
        // Use data access helper components to retrieve data

    public int CreateCustomer( string strName, string strAddress, string DateTime dtDOB )
        // Use data access helper components to create a new customer entry in the database
        // and return customer ID

    public void DeleteCustomer( int nCustomerID )
        // Use data access helper components to delete customer from the database

    public void UpdateCustomer( DataSet dsCustomer )
        // Use data access helper components to update customer in the database

// Code in some business component
CustomerDALC             dalc = new CustomerDALC();
CustomerBusinessEntity   be = dalc.GetCustomer( 123 );

Exception Handling in Data Access Logic Components

Data Access Logic Components should propagate exceptions back to direct callers. The following example illustrates:

public class CustomerDALC
    public void LoadCustomers()
            // Load all customers from database
        catch ( Exception ex )
            threw new DataAccessException ( ex.Message );
            // Cleanup

    public UpdateCustomers() { ... }
    public DeleteCustomer() { ... }
    public AddCustomers ( CustomerBusinessEntities collBE ) { ... }

Data Access Helper Components

Centralize generic data access functionality in a data access helper component can help produce cleaner code and a more manageable design. Consider data access helper component as a generic caller-side facade to the data store. They are typically agnostics to the application logic being performed.

If you are designing your application to be agnostic to the data source being used (for example, to be able to access Oracle, SQL Server and so on), you would have two data access helper components, one that use the ADO.NET provider classes for Oracle (OracleCommand, ... ), and another helper component that uses ADO.NET provider for SQL Server (SqlCommand, ... ). You can then use the Factory pattern to create the appropriate component while providing a uniform interface to both components.

In general, the goals of a data access helper components are:

The Data Access Application Block for .NET should be used as a model on how to design data access helper components for .NET

Integrating with Services

If your business process talks to external services, then you will need to handle the semantics of calling each service that you want to communicate with. Specifically:

  1. You will need to use the correct communication API and perform any necessary translation between the data formats used by the service and those used by your business process.
  2. If calling an external service also involves long-running conversations, then you will also need to keep intermediate state while waiting for a response.

Think of service agents as data access logic components for services rather than for data stores. You can also think of service agents as proxies to other services. The goals of using a service agent are therefore:

In certain scenarios, service agents may receive asynchronous data from business components. Service agents may also send asynchronous data to services. When messages are exchanged asynchronously, you need to keep track of the conversation state -which conversation does a set of message belong to. There are two options:

Next Chapter

This chapter described general recommendation for designing different kinds of component commonly found in distributed systems. The next chapter discusses the effect of various policies (security, communication, etc. ) on the design of the application.