Chapter 22: Designing Rich Client Applications
For more details of the topics covered in this guide, see Contents of the Guide.
- General Design Considerations
- Specific Design Issues
- Security Considerations
- Data Handling Considerations
- Offline/Occasionally Connected Considerations
- Technology Considerations
- Deployment Considerations
- Relevant Design Patterns
- Additional Resources
In this chapter, you will learn about the key scenarios for using rich client applications, the components found in a rich client application, and the important design considerations for rich client applications. You will also learn about deployment scenarios for rich client applications, and the key patterns and technology considerations for designing rich client applications.
Rich client UIs can provide high performance, interactive, and rich user experiences for applications that must operate in stand-alone, connected, occasionally connected, and disconnected scenarios. Windows Forms, Windows Presentation Foundation (WPF), and Microsoft Office Business Application (OBA) development environments and tools are available that allow developers to quickly and easily build rich client applications.
While these technologies can be used to create stand-alone applications, they can also be used to create applications that run on the client machine but communicate with services exposed by other layers (both logical and physical) and other applications that expose operations the client requires. These operations may include data access, information retrieval, searching, sending information to other systems, back up, and related activities. Figure 1 shows an overall view of typical rich client architecture, and identifies the components usually found in each layer.
Overall view of typical rich client architecture
A typical rich client application is decomposed into three layers: the presentation layer, business layer and data layer. The presentation layer usually contains UI and presentation logic components; the business layer usually contains business logic, business workflow and business entity components; and the data layer usually contains data access and service agent components. For more information about layered design, see Chapter 5, "Layered Application Guidelines." For more information about the components appropriate for each layer, see Chapter 10 "Component Guidelines."
Rich client applications may be fairly thin applications consisting of mainly a presentation layer, which access a remote business layer hosted on server machines through services. An example of this is a data entry application that sends all of the data to the server for processing and storage.
At the other end of the scale, they may be complex applications that perform most of the processing themselves and only communicate with other services and data stores to consume or send back information. An example of this is an application such as Microsoft Excel® spreadsheet software that performs complex local tasks, stores state and data locally and only communicates with remote servers to fetch and update linked data. These types of rich clients may contain their own business layers and data access layers. The guidelines for the business and data layers in such applications are the same as those discussed generally for all applications.
General Design Considerations
When designing a rich client application, the goal of the software architect is to choose an appropriate technology and design a structure that minimizes complexity by separating tasks into different areas of concern. The design should meet the requirements for the application in terms of performance, security, reusability, and ease of maintenance.
Consider the following guidelines when designing rich client applications:
- Choose an appropriate technology based on application requirements. Suitable technologies include Windows Forms, WPF, XAML Browser Applications (XBAP), and OBA.
- Separate presentation logic from interface implementation. Consider design patterns such as Presentation Model and Supervising Presenter (or Supervising Controller) that separate UI rendering from UI logic; which eases maintenance, promotes reusability, and improves testability. The use of separate components within the application can reduce dependencies, make maintenance and testing easier, and promote reusability.
- Identify the presentation tasks and presentation flows. This will help you to design each screen and each step in a multi screen or Wizard process.
- Design to provide a suitable and usable interface. Take into account features such as layout, navigation, choice of controls, and localization to maximize accessibility and usability.
- Apply separation of concerns across all layers. For example, extract business rules and other tasks not related to presentation and locate these in a separate business layer. Separate data access code into separate components located in a data layer.
- Reuse common presentation logic. Libraries that contain templates, generalized client-side validation functions, and helper classes may be reusable in several applications.
- Loosely couple your client from any remote services it uses. Use a message-based interface to communicate with services located on separate physical tiers.
- Avoid tight coupling to objects in other layers. Use the abstraction provided by common interface definitions, abstract base classes, or messaging when communicating with other layers of the application. For example, implementing the Dependency Injection and Inversion of Control patterns can provide a shared abstraction between layers.
- Reduce round trips when accessing remote layers. Use coarse-grained methods and execute them asynchronously if possible to avoid blocking or freezing the UI.
Specific Design Issues
There are several common issues that you must consider as your develop your design. These issues can be categorized into specific areas of the design. The following sections contain guidelines to help you resolve the common issues in each area:
- Business Layer
- Configuration Management
- Data Access
- Exception Management
- Presentation Layer
- State Management
A typical thin rich client acts as the interface to a business system, and the business layer is part of that business system and is usually exposed as a service. However, in a typical thick rich client, the business layer is located on the client itself. Consider the following guidelines when designing the business layer for a rich client:
- Identify the business layers and service interfaces that the application will use. If the application will access remote services, import the interface definitions and write code that accesses these service functions using the interfaces. This helps to minimize coupling between the client and a remote business layer or services that it uses.
- If your business logic does not contain sensitive information, consider locating some of the business rules on the client to improve performance of the UI and the client application. If your business logic does contain sensitive information, you should locate the business layer on a separate tier.
- Consider how the client will obtain information required to operate business rules and other client-side processing, update this information automatically as it changes, and how users or administrators will update the business rules as requirements change. You may decide to have the client obtain business rule information from a remote server when it starts up.
For more information about designing the business layer, see Chapter 7 "Business Layer Guidelines."
If the business and data layers of a rich client application are located on a remote tier and exposed as services, or if a rich client uses other remote services, it can communicate with these services using a variety of protocols and methods. These may include HTTP requests, Simple SMTP e-mail messages, SOAP Web service messages, DCOM for remote components, remote database access protocols, or other TCP/IP-based standard or custom communication protocols. If the business layer and data layer are located on the client, the presentation layer can use object-based methods to interact with them. Consider the following guidelines when designing a communication strategy:
- When communicating with services on a remote physical tier, use a message-based protocol when possible. This gives you a more natural way to make asynchronous calls to avoid blocking the presentation layer, and to support load balanced and failover server configurations. Use coarse-grained interfaces to minimize network traffic and maximize performance.
- Where required, enable offline processing for the application. Detect and monitor the connection state. When disconnected, cache information locally and then resynchronize when communication is re-enabled. Consider holding application state and data locally in a persistent cache to allow disconnected start up and a shutdown/restart cycles without information loss.
- To protect sensitive information and communication channels, consider using IPSec and SSL to secure the channel, encryption to protect data, and digital signatures to detect data tampering.
- If the application must consume or send large sets or amounts of data, consider the potential performance and network impact. Choose more efficient communication protocols such as TCP, using compression mechanisms to minimize the data payload size for message-based protocols such as SMTP and SOAP, or custom binary formats when the application does not need to support open communication standards.
For more information about communication between clients and layers of the application, see Chapter 18 "Communication and Messaging."
To maximize extensibility and maintainability of the application—particularly where it exposes a complex UI as is common in many business scenarios—consider implementing the interface using the Composition design pattern, where the UI consists of separate modules or forms loaded dynamically at run time. This approach is useful when users may open several forms to perform specific tasks, and work with data in a range of different ways. Users can open and close forms as required, and the application can maximize performance and reduce start up delays by loading these forms only when required. Also consider how you can support personalization for users, so that they can modify the layout and content to suit their own requirements. Consider the following guidelines when designing a composition strategy:
- Based on functional specifications and requirements, identify the appropriate types of interface components you require. For example, possible components include Windows Forms, WPF forms, Office-style documents, user controls, or custom modules.
- Identify an appropriate composition mechanism, where composition is appropriate, and consider composing views from reusable modular parts. For example, use the Composite View pattern to build a view from modular, atomic component parts. You may alternatively decide to use a composition framework such as the patterns & practices Composite Client Application Guidance, or built-in features of your development environment such as user controls or document panels. However, be careful with dependencies between components, and use abstraction patterns when possible to avoid issues with maintainability. Implement, where possible, features for managing auto update and versioning of composable components.
- If you must support communication between different forms and presentation components that make up a composite interface, consider implementing decoupled communication techniques such as the Publish/Subscribe or Command pattern. This will minimize the coupling between these components and improve testability.
- Take advantage of appropriate templates and data binding techniques available in your chosen implementation technology to simplify and minimize the code required for each form that you use within a composable interface.
- Consider implementing personalization so that users can customize the layout of composable components within the interface.
Rich client applications will usually require configuration information loaded at startup, and sometimes during execution. This information may be network or connection information, user settings, UI business rules, or general display and layout settings. You may decide to store some or all of this information locally, or download it from a remote server when the application starts. You may also need to persist changes to the information as the application runs or when it ends; for example, storing user preferences, layout settings, and other UI data in the user's local profile. Consider the following guidelines when designing a configuration management strategy:
- Determine what configurable data may change during the life of your application; for example, file locations, developer versus production settings, logging, assembly references, and contact information for notifications. If necessary, design the application to detect and dynamically apply the configuration changes.
- Choose local or centralized storage locations. User managed data (including profile information or personalization settings) should generally be stored locally, though you may consider storing it centrally to enable roaming. Global application settings should be stored in a central location, and perhaps downloaded locally for performance reasons.
- Identify sensitive configuration information and implement a suitable mechanism for protecting it during transit over the network, when persisted locally, and even when stored in memory.
- Take into account any global security policies and Group Policy overrides that might affect or override local configurations.
Rich client applications will usually access data stored on a remote server, as well as data stored on the local machine. Data access often has a significant impact on performance, and is the most obvious factor in the user's perception of an application and its usability and responsiveness. You should aim to maximize performance of data access routines and data transmission across tiers. You must also design the application with regard to the types of data it will use. If the client application cannot handle the data in the exposed format, you must implement a translation mechanism that converts it. However, this will have an impact on performance. Consider the following guidelines when designing a data access strategy:
- Whenever possible, load data asynchronously so that the UI is still responsive while the data is loading. However, you must also be aware of conflicts that might occur if the user attempts to interact with the data before loading is complete, and design the interface to protect against errors arising from this.
- If the client will consume very large amounts of data, consider chunking these and loading them asynchronously into a local cache to improve performance. You must plan how you will handle inconsistencies between the local copy and the original data, perhaps by using methods such as time stamps or events.
- In occasionally connected scenarios, monitor connectivity and implement a service dispatcher mechanism to support batch processing so that users can perform multiple updates to data.
- Determine how you will detect and manage concurrency conflicts that arise when multiple users attempt to update the central data store. Explore optimistic and pessimistic concurrency models.
For more information about data access and handling data in rich client applications, see "Data Handling Considerations" later in this chapter.
All applications and services are subject to the occurrence of errors and exceptions, and you must implement a suitable strategy for detecting and managing these errors and exceptions. A robust and well designed exception management strategy can simplify application design, and improve security and manageability. It can also make it easier for developers to create the application, and reduces development time and cost. In a rich client application, you will usually need to notify the user. In addition, for anything other than trivial UI errors such as validation messages, you should consider logging errors and exceptions for use by operations staff and monitoring systems. The main challenge here is usually collating log information or designing a centralized server-based logging sink that can be accessed by all clients. Consider the following guidelines when designing an exception management strategy:
- Identify the errors and exceptions that are likely to arise within the application, and identify which of these require only user notification. Errors such as validation failures are usually only notified locally to the user. However, errors such as repeated invalid logon attempts or detection of malicious data should be logged and administrators notified. All execution exceptions and application failures should be logged and, optionally, administrators notified.
- Identify an overall strategy for handling exceptions. This may involve actions such as wrapping exceptions with other application specific or custom exceptions that contain additional data to assist in resolving failures, or replacing exceptions to prevent exposure of sensitive information. Also, implement a mechanism for detecting and logging unhandled exceptions. A framework for managing exceptions, such as the patterns & practices Enterprise Library, may be useful for these tasks.
- Determine how you will store exception information, how you will pass it to other layers of the application if required, and how you will notify administrators. Consider using a monitoring tool or environment that can read events from the local machine and present a view of the application state to administrators.
- Ensure that you sanitize exception information that is exposed to users in order to prevent sensitive information from being displayed or stored in log and audit files. If necessary, encrypt information and use secure channels to communicate exceptions and errors to other physical tiers of the application.
- Only catch exceptions that you can handle. For example, catch data conversion exceptions that can occur when trying to convert null values. Do not use exceptions to control business logic.
For more information about exception handling, see Chapter 17 "Crosscutting Concerns."
It is vital to minimize maintenance cost and effort for all applications and components. You should implement mechanisms that reduce maintenance liabilities; for example, by using design patterns that provide good separation of concerns and loose coupling between components. Rich client applications are usually located on remote client machines, and are subsequently more difficult to operate than server installed applications. Other issues to consider, therefore, include deployment, updates, patches, and versioning. Consider the following guidelines when designing a maintainability strategy:
- Implement a suitable mechanism for manual and/or automatic updates to the application and its components. You must take into account versioning issues to ensure that the application has consistent and interoperable versions of all the components it uses.
- Choose an appropriate deployment approach based on the environment in which your application will be used. For example, you might require an installation program for applications that are publically available, or you may be able to use system tools such as Microsoft System Center to deploy applications within a closed environment.
- Design the application so that components are loosely coupled and interchangeable where possible. This allows you to change individual components depending on requirements, run-time scenarios, and individual user requirements or preferences. Also, design to minimize dependencies between components and layers so that the application or the individual layers and components can be used in different scenarios where appropriate.
- Implement logging and auditing as appropriate for the application to assist administrators and developers when debugging the application and solving run-time problems.
For more information about maintainability, see Chapter 16 "Quality Attributes."
The presentation layer is the part of the application that the user sees and interacts with, and it must therefore satisfy many requirements. These requirements encompass general factors such as usability, performance, design, and interactivity. A poor user experience can result in a severely negative impact on an application that performs well in all other respects. It is important to design your application to support a compelling and intuitive user experience from the outset, as the user experience is influenced by many different aspects of your application's architecture. Consider the following guidelines when designing the presentation features of your application:
- Investigate how you can separate the logic for managing user interaction from the UI, and from the data with which the user works—perhaps by applying a Separated Presentation style. This makes it easier to update parts of the application, allows developers and designers to work separately on the components, and improves testability.
- Implement command and navigation strategies and mechanisms that are flexible and can be updated easily. Consider implementing well-known design patterns such as Command, Publish/Subscribe, and Observer to decouple commands and navigation from the components in the application and to improve testability.
- Take advantage of data binding capabilities to display data whenever possible, especially for tabular and multirow data presentation. This reduces the code required, simplifies development, and reduces coding errors. It can also automatically synchronize data in different views or forms. Use two-way binding where the user must be able to update the data.
- Consider how you will display documents in an Office document—style interface, or when displaying document content or HTML in other UI elements. Ensure that the user is protected from invalid and malicious content that might reside in documents.
- Ensure that the application UI can be internationalized and then localized to all geographical and cultural scenarios where it may be used. This includes changing the language, text direction, and content layout based on configuration or auto detection of the user's culture. Also, ensure that you provide appropriate support for accessibility and navigation.
For more information about presentation layer design considerations, see Chapter 6 "Presentation Layer Guidelines."
State management concerns the persistence of data that represents the state of a component, operation, or step in a process. State data may include user settings, configuration information, workflow information, business rule values, and data that the UI displays. The application must be able to save this data, access it as required, and handle conflicts, restarts, and connection status changes. Consider the following guidelines when designing a state-management strategy:
- Determine the state information that the application must store, including estimates of the size, the frequency of changes, and the processing or overhead cost of re-creating or refetching the data; and ensure that your chosen state management mechanism can provide appropriate support.
- If you have large volumes of state data, consider using a local disk-based mechanism to store it. If the application requires data to be available when it starts up, use a persistent mechanism such as isolated storage or a disk file.
- When storing sensitive data, ensure that you implement the appropriate level of protection by using encryption and/or digital signatures.
- Consider at what granularity you must maintain state information. For example, determine the state information that applies to all users of an application and the information that applies only to specific users or roles.
Some rich client applications require view flow or workflow support to enable multistep operations or Wizard-style UI elements. You can implement these features using separate components or custom solutions, or you can take advantage of a framework such as Windows Workflow Foundation (WF). Consider the following guidelines when designing a workflow strategy:
- Use workflow within business components for operations that involve multistep or long-running processes. Consider creating separate components to implement your workflow and view flow tasks. This reduces dependencies and makes it easier to interchange components as requirements change.
- For simple workflow and view flow requirements, it is usually sufficient to use custom code based on well-known patterns such as Use Case Controller and ViewFlow. For workflow and view flow requirements that are more complex, consider using a workflow engine such as WF.
- Consider how you will capture, manage, and display errors in workflows. Also, identify how you will handle partially completed tasks, and whether it is possible to recover from a failure and continue the task or whether you must restart the process.
For more information about workflow components, see Chapter 14 "Designing Workflow Components."
Security encompasses a range of factors and is vital in all types of applications. Rich client applications must be designed and implemented with security in mind, and—where they act as the presentation layer for business applications—must play their part in protecting and securing the other layers of the application. Security issues involve a range of concerns, including protecting sensitive data, user authentication and authorization, guarding against attack from malicious code and users, and auditing and logging events and user activity. Consider the following guidelines when designing a security strategy:
- Determine the appropriate technology and approach for authenticating users, including support for multiple users of the same rich client application instance. You should consider how and when to log on users, whether you must support different types of users (different roles) with differing permissions (such as administrators and standard users), and how you will record successful and failed logons. Take into account the requirements for disconnected or offline authentication where this is relevant.
- Consider using Windows Integrated Authentication or a federated authentication solution if users must be able to access multiple applications with the same credentials or identity. If you cannot use Windows Integrated Authentication, you may be able to use an external agency that offers federated authentication support. If you cannot use an external agency, consider using a certificate-based system, or create a custom solution for your organization.
- Consider the requirement to validate inputs, both from the user and from sources such as services and other application interfaces. You might need to create custom validation mechanisms, or you might be able to take advantage of the validation features of the technology you are working with. The Microsoft Visual Studio® Windows Forms development environment contains validation controls. Alternatively, consider a third party validation framework such as the Enterprise Library Validation Application Block, which provides comprehensive features for validation in the UI and in the business layer. Irrespective of your validation choice, remember that you must always validate data when it crosses trust boundaries.
- Consider how you will protect data stored in the application and in resources such as files, caches, and documents used by the application. Encrypt sensitive data where it might be exposed, and consider using a digital signature to prevent tampering. In maximum security applications, consider encrypting volatile information stored in memory. Also, remember to protect sensitive information that is sent from the application over a network or communication channel.
- Consider how you will implement auditing and logging for the application, and what information to include in these logs. Remember to protect sensitive information in the logs using encryption, and optionally use digital signatures for the most sensitive information that is vulnerable to tampering.
Data Handling Considerations
Application data can be made available from server-side applications through a Web service. Cache this data on client to improve performance and enable offline usage. Rich client applications can also use local data. Data use by rich client applications falls into two categories:
- Read-only reference data. This is data that does not change often and is used by the client for reference purposes, such as a product catalog. Store reference data on the client to reduce the amount of data interchange between the client and the server in order to improve the performance of your application, enable offline capabilities, provide early data validation, and generally improve the usability of your application.
- Transient data. This is data that can be changed on the client as well as on the server. One of the most challenging aspects of dealing with transient data in rich client applications is dealing with concurrency issues where the same data can be modified by multiple clients at the same time. You must keep track of any client-side changes made to transient data on the client and manage updates on the server that may contain conflicting changes.
Rich clients often must cache data locally, whether it is read-only reference data or transient data. Caching data can improve performance in your application and provide the data necessary to work offline. To enable data caching, rich client applications should implement some form of caching infrastructure that can handle the data caching details transparently. The common types of caching are:
- Short term data caching. Data is not persistent, so the application cannot run offline.
- Long term data caching. Caching data in a persistent medium, such as isolated storage or the local file system, allows the application to work when there is no connectivity to the server. Rich client applications should differentiate between data that has been successfully synchronized with the server and data that is still tentative.
When serving multiple clients simultaneously, changes to the data held on the server can occur before a specific client's changes can be synchronized with the server. This can lead to data corruption or inconsistencies. You must, therefore, implement a mechanism to ensure that any data conflicts are handled appropriately when the data is synchronized, and that the resulting data is consistent and correct. Common approaches for handling data concurrency are:
- Pessimistic concurrency. Pessimistic concurrency assumes that the risk of a data conflicts is high. To prevent data conflicts, it allows one client to maintain a lock over the data, thereby preventing any other clients from accessing or modifying the data until the client's own changes are completed and committed. This pattern is also known as the pessimistic offline lock pattern.
- Optimistic concurrency. Optimistic concurrency assumes that the risk of data conflicts is low. With optimistic concurrency, the data is not locked by a client while it is being updated. To detect data conflicts, the original data and the changed data are both sent to the server. The original data is checked against the current data to see if it has been updated since it was last retrieved. If not, the changes are applied; otherwise a data conflict exception is raised. This pattern is also known as the optimistic offline lock pattern.
The ADO.NET DataSet helps clients to work with data while offline. DataSets can keep track of local changes made to the data, which makes it easier to synchronize the data with the server and reconcile data conflicts. DataSets can also be used to merge data from different sources.
Windows Forms, WPF, and Silverlight data binding supports bidirectional binding that allows you to bind a data structure to a UI component, display the current data values to the user, allow the user to edit the data, and then automatically update the underlying data using the values entered by the user. Data binding can be used to display read-only data to users, allow users to update data within the UI, provide master\detail views of data, allow users to explore complex related data items, and provide lookup table functionality that allows the UI to display user friendly names for data items instead of data row key values.
For more information about designing the data layer, see Chapter 8 "Data Layer Guidelines." For more information about designing data components for rich client applications, see Chapter 15 "Designing Data Components."
Offline/Occasionally Connected Considerations
An application is occasionally connected if, during unspecified periods, it cannot interact with services or data over a network in a timely manner. Occasionally connected rich client applications are capable of performing work when not connected to a networked resource, and can update the networked resources in the background when a connection is available.
When designing occasionally connected applications, aim to favor asynchronous communication when interacting with data and services over a network and minimize or eliminate complex interactions with network located data and services. This makes it easier to implement a synchronization mechanism for use when a connection is available.
In order to work when disconnected, your application should implement data caching capabilities that provide all of the data necessary on the client for the user to continue working when offline. You must also determine how to prevent the application using stale data. In general, you should consider designing a store and forward mechanism where messages are created, stored while disconnected, and eventually forwarded to their respective destinations when a connection becomes available. The most common implementation of store and forward is a message queue.
Consider the following two approaches when designing for an occasionally connected scenario:
- Data centric. Applications that use the data centric strategy have a relational database management system (RDBMS) installed locally on the client, and use the built-in capabilities of the database system to propagate local data changes back to the server, handle the synchronization process, and detect and resolve any data conflicts.
- Service oriented. Applications that use the service-oriented approach store information in messages, and arrange these messages in queues while the client is offline. After the connection is reestablished, the queued messages are sent to the server for processing.
There are several different technologies available that you can use to implement a rich client application. The following guidelines will help you to choose an appropriate implementation technology, and provide guidance on the use of appropriate patterns and system functions for configuration and monitoring:
- Choose a suitable development technology:
- Consider WFP for applications that will fully support rich media and graphics.
- Consider using Windows Forms if you have existing Windows Forms investments, or if you are building LOB applications that do not require rich visualization and should execute with minimal hardware requirements.
- Consider XBAP for applications that are downloaded from a Web server and then execute in the browser.
- Consider OBA for applications that are predominantly document-based, or are used for reporting.
- Explore patterns & practices assets that can help you to design and implement the application:
- Consider using the Smart Client Software Factory if you decide to use Windows Forms and you are designing composite interfaces.
- Consider using the Composite Client Application Guidance if you decide to use WPF and/or Silverlight, and you wish to develop modular applications that typically feature multiple screens, rich, flexible user interaction and data visualization, and role-determined behavior.
- Consider Enterprise Library to help you implement solutions for crosscutting concerns such as exception handling, caching, and validation.
- If you decide to use WPF:
- Consider implementing the Presentation Model or View Model pattern to make the UI logic unit testable and to make it easier to re-skin your application.
- WPF allows you to attach additional behaviors to existing control implementations. Use this approach instead of attempting to subclass a control.
- If you want to support remote administration and monitoring:
- Consider implementing Group Policy overrides for your application configuration. This is required to meet Certified for Windows logo requirements.
- Consider using technologies such as SNMP and WMI to expose exceptions and health state.
There are several options for the deployment of rich client applications. You might have a stand-alone application where all of the application logic, including data, is deployed on the client machine. Another option is client/server, where the application logic is deployed on the client and the data is deployed on a database tier. Finally, there are several n-tier options where one or more application servers host part of the application logic.
Figure 2 illustrates a stand-alone deployment where all of the application logic and data is deployed on the client.
Stand-alone deployment for a rich client application
In a client/server deployment, all of the application logic is deployed on the client and the data is deployed on a database server, as shown in Figure 3.
Client/server deployment for a rich client application
In an n-tier deployment, you can place presentation and business logic on the client, or only the presentation logic on the client. Figure 4 illustrates the case where the presentation and business logic are deployed on the client.
N-tier deployment with the business layer located on the client tier
Figure 5 illustrates the case where the business and data access logic are deployed on an application server.
N-tier deployment with the business layer located on the application tier
For more information on deployment strategies, see Chapter 19 "Physical Tiers and Deployment."
Several options exist for deploying a rich client application to a physical machine. Each has specific advantages and liabilities, and you should research the options to ensure that the one you choose is suitable for the target environments in which your application will execute. The options are the following:
- Click Once deployment. This approach requires little user interaction, provides automated updates, and requires little effort for the developer. However, it can only be used to deploy a single solution that is not part of a larger solution; it cannot deploy additional files or registry keys; it cannot interact with the user to configure the installation; and it cannot provide a branded installation.
- XCOPY deployment. If no registry settings or component registration are required, the executable can be copied directly to the client machine hard disk.
- Windows Installer (.MSI) package. This is a comprehensive setup program that can install components, resources, registry settings, and other artifacts required by the application. Users require administrator privileges to install MSI packages themselves. There are solutions available, such as Microsoft System Center Configuration Manager, for distributing applications in a corporate environment.
- XBAP package. The application is downloaded through the browser and runs in a constrained security environment on the machine. Updates can be pushed to the client automatically.
Relevant Design Patterns
Key patterns are organized into categories such as Communication, Composition, Configuration Management, Exception Management, Presentation, State Management, and Workflow; as shown in the following table. Consider using these patterns when making design decisions for each category.
Asynchronous Callback. Execute long-running tasks on a separate thread that executes in the background, and provide a function for the thread to call back into when the task is complete.
Gateway. Provide access to an external system through a common abstract interface so that consumers are not required to understand the external system interface.
Service Locator. Centralize distributed service object lookups, provide a centralized point of control, and act as a cache that eliminates redundant lookups.
Service Agent and Proxy. Implement a component that the consuming application can use without knowing that it is not accessing the actual target component or service. The component passes calls to the remote component or service, and returns the result to the consuming application. The proxy abstracts the details of communication with other remote components, typically when using ASMX or WCF services.
Service Interface. A programmatic interface that other systems can use to interact with the service.
Composite View. Combine individual views into a composite view
Template View. Implement a common template view, and derive or construct views using the template view.
Two-Step View. Transform the model data into a logical presentation without any specific formatting, and then convert that logical presentation into the actual formatting required.
View Helper. Delegate business data processing responsibilities to helper classes.
Provider. Implement a component that exposes an API that is different from the client API in order to allow any custom implementation to be seamlessly plugged in.
Exception Shielding. Prevent a service from exposing information about its internal implementation when an exception occurs.
Application Controller. An object that contains all of the flow logic and is used by other Controllers that work with a Model and display the appropriate View.
Model-View-Presenter. Separate request processing into three roles, with the View being responsible for handling user input, the Model responsible for application data and business logic, and the Presenter responsible for presentation logic and for coordinating the interaction between the View and the Model.
Model-View-ViewModel. A variation of Model-View-Controller (MVC) that is tailored for modern UI development platforms where the View is the responsibility of a designer rather than a classic developer.
Presentation Model. Separate the responsibilities for the visual display of the user interface and the presentation state and behavior into different classes named, respectively, the view and the presentation model. The view class manages the user interface controls and encapsulates any visual state or behavior that is specific to the UI. The presentation model class encapsulates presentation behavior and state and acts as a façade onto the underlying model.
Context Object. An object used to manage the current execution context.
View Flow. Manage navigation from one view to another based on state in the application or environment, and the conditions and limitations required for correct operation of the application.
Work Flow. Manage the flow of control in a complex process-oriented application in a predefined manner while allowing dynamic route modification through decision and branching structures that can modify the routing of requests.
For more information on the Template View, Transform View, and Two-Step View patterns, see Fowler, Martin. Patterns of Enterprise Application Architecture. Addison-Wesley, 2002. Or at http://martinfowler.com/eaaCatalog/.
For more information on the Provider pattern, see "Provider Model Design Pattern and Specification, Part I" at https://msdn.microsoft.com/en-us/library/ms998421.aspx.
For more information on the Asynchronous Callback pattern, see "Creating a Simplified Asynchronous Call Pattern for Windows Forms Applications" at https://msdn.microsoft.com/en-us/library/ms996483.aspx.
For more information on the Service Interface pattern, see "Service Interface" at https://msdn.microsoft.com/en-us/library/ms998421.aspx.
For more information on the Exception Shielding pattern, see "Useful Patterns for Services" at https://msdn.microsoft.com/en-us/library/cc304800.aspx.
For more information on the Composite View pattern, see "Patterns in the Composite Application Library" at https://msdn.microsoft.com/en-us/library/dd458924.aspx.
For more information on the Presentation Model pattern, see "Presentation Model" at https://msdn.microsoft.com/en-us/library/dd458863.aspx.
For more information, see the following resources:
- For more information on building composite applications, see "Composite Client Application Guidance" at https://msdn.microsoft.com/en-us/library/cc707819.aspx.
- For more information on designing rich client and smart client applications, see the "Smart Client Architecture and Design Guide" at https://msdn.microsoft.com/en-us/library/ms998506.aspx.
- For more information on caching architectures, see the "Caching Architecture Guide for .NET Framework Applications" at https://msdn.microsoft.com/en-us/library/ms978498.aspx.
- For more information on deployment scenarios and considerations, see "Deploying .NET Framework-based Applications" at https://msdn.microsoft.com/en-us/library/ms954585.aspx.