Note that the information on this page is the BETA 1 of a guide that is now released. See
http://www.codeplex.com/AppArchGuide for the latest PDF and HTML content.
Chapter 24 – Web Application Archetype
- J.D. Meier, Alex Homer, David Hill,
Prashant Bansode, Lonnie Wall, Rob Boucher Jr, Akshay Bogawat
- Learn the general design considerations for a Web application.
- Learn the guidelines for the key attributes of a Web application.
- Learn the guidelines for the layers within a Web application.
- Learn the guidelines for performance, security, and deployment.
- Understand the technology choices for a Web application.
The core of a Web application is its server-side logic. The Web application layer itself can be comprised of many distinct layers. The typical example is a three-layered architecture comprised of presentation, business, and data layers. The following diagram
illustrates a common Web application architecture with common components grouped by different areas of concern.
When designing a Web application, the goals of a software architect are to minimize the complexity by separating tasks into different areas of concern while designing a secure and high performance application.
When designing Web application, consider following guidelines:
- Partition your application logically. Use layering to logically partition your application logic into presentation, business, and data access layers. This helps you to create maintainable code, and allows you to monitor and optimize the performance
of each layer separately. A clear logical separation also offers more choices for scaling your application.
- Use abstraction to implement loose coupling between layers. This can be accomplished by defining interface components, such as a façade with well-known inputs and outputs that translates requests into a format understood by components within
the layer. In addition, you can also use Interface types or abstract base classes to define a shared abstraction that must be implemented by interface components.
- Understand how components will communicate with each other. This requires an understanding of the deployment scenarios your application must support. You must determine if communication across physical boundaries or process boundaries should be supported,
or if all components will run within the same process.
- Reduce round trips. When designing a Web application, consider using techniques such as caching and output buffering to reduce round trips between the browser and the Web server, and between the Web server and downstream servers.
- Consider using caching. A well-designed caching strategy is probably the single most important performance-related design consideration. ASP.NET caching features include output caching, partial page caching, and the cache API. Design your application
to take advantage of these features.
- Consider using logging and instrumentation. You should audit and log activity across the tiers of your application. These logs can be used to detect suspicious activity, which frequently provides early indications of an attack on the system.
- Avoid blocking during long-running tasks. If you have long-running or blocking operations, consider using an asynchronous approach to allow the Web server to process other incoming requests.
- Consider authenticating users across trust boundaries. You should design your application to authenticate users whenever they cross a trust boundary; for example, when accessing a remote business layer from your presentation layer.
- Do not pass un-encrypted sensitive data across network. Whenever you need to pass sensitive data such as a password or authentication cookie across the network, consider encrypting and signing the data or using SSL.
- Design to run you Web application using a least-privilege account. If an attacker manages to take control of a process, the process identity should have restricted access to the file system and other system resources in order to limit the possible
Web Application Frame
||Lack of authentication across trust boundaries.
||Storing passwords in a database as plain text.
||Designing custom authentication mechanism instead of using built-in capabilities.
||Lack of authorization across trust boundaries.
||Incorrect role granularity.
||Using impersonation and delegation when not required.
||Caching volatile data.
||Not considering caching page output.
||Caching sensitive data.
||Failing to cache data in a ready-to-use format.
||Revealing sensitive information to the end user.
||Not logging sufficient details about the exception.
||Using exceptions for application logic.
|Logging and Instrumentation
||Failing to implement adequate instrumentation in all layers.
||Failing to log system-critical and business-critical events.
||Not supporting runtime configuration of logging and instrumentation.
||Logging sensitive information.
||Mixing navigation logic with user interface components.
||Hard-coding relationships between views.
||Not verifying if the user is authorized to navigate to a view.
|Page Layout (UI)
||Using table-based layout for complex layouts.
||Designing complex and overloaded pages.
||Using excessive postbacks that impact user experience.
||Using excessive page sizes that reduce performance.
||Creating custom entity objects when not required.
||Adding business logic to presentation entities.
||Mixing processing and rendering logic.
||Choosing an inappropriate pattern.
|Service Interface Layer
||Breaking the service interface.
||Implementing business rules in a service interface.
||Failing to consider interoperability requirements.
||Using an incorrect state store.
||Not considering serialization requirements.
||Not persisting state when required.
||Enabling view state for large data items such as Datasets
||Relying on client side validation.
||Lack of validation across trust boundaries.
||Not reusing the validation logic.
Designing an effective authentication strategy is important for the security and reliability of your application. Improper or weak authorization can leave your application vulnerable to spoofing attacks, dictionary attacks, session hijacking, and other types
When designing an authentication strategy, consider following guidelines:
- Identify trust boundaries within Web application layers. This will help you to determine where to authenticate.
- Use a platform-supported authentication mechanism such as Windows Authentication when possible.
- If you are using Forms authentication, use the platform features when possible.
- If you are using Forms authentication, protect your authentication cookies.
- If you are not using SSL, consider reducing the session timeout to minimize exposure of your authentication cookies.
- Separate the public and the restricted areas of your Web application.
- Enforce strong account management practices such as account lockouts and expirations.
- Enforce strong passwords policies. This includes specifying password length and complexity, and password expiration policies.
- Do not store passwords in a database or data store. Instead, store a hash of the password.
- Protect access to your credential store.
Authorization determines the tasks that an authenticated identity can perform and identifies the resources that can be accessed. Designing an effective authorization strategy is important for the security and reliability of your application. Improper or weak
authorization leads to information disclosure, data tampering, and elevation of privileges. Defense in depth is the key security principle to apply to your application's authorization strategy.
When designing an authorization strategy, consider following guidelines:
- Identify trust boundaries within the Web application layers.
- Use URL authorization for page and directory access control.
- Use the ASP.NET role manager for roles authorization.
- If your role lookup process is expensive, consider caching role information.
- Consider the granularity of your authorization settings.
- Protect your authorization cookie using encryption, or set the HttpOnly property to prevent access from client-side script.
- Access downstream resources with a trusted identity using the trusted sub-system model.
- Use impersonation and delegation to take advantage of the user-specific auditing and granular access controls of the platform, but consider the effect on performance and scalability.
Caching improves the performance and responsiveness of your application. However, incorrect caching choices and poor caching design can degrade performance and responsiveness. You should use caching to optimize reference data lookups, avoid network round trips,
and avoid unnecessary and duplicate processing. To implement caching, you must decide when to load the cache data. Try to load the cache asynchronously or by using a batch process to avoid client delays.
When designing caching, consider following guidelines:
- Avoid caching data on per-user basis.
- Cache application-wide data and data used by multiple users.
- Avoid caching volatile data.
- Use output caching to cache pages that are relatively static.
- Consider using partial page caching through user controls for static data in your pages.
- Choose the appropriate cache location; such as client, proxy server, or Web server.
- Pool shared resources that are expensive, such as network connections, instead of caching them.
- Cache data in a ready-to-use format.
- For large caches, consider loading the cache asynchronously with a separate thread, or by using a batch process.
- Consider caching data in the presentation layer that must be displayed to the user.
- Consider caching in the business layer when the data cannot be efficiently retrieved from the database.
- If you need to cache large amounts of data for long periods, cache it in a database.
- Avoid using distributed coherent caches.
Designing an effective exception management strategy is important for the security and reliability of your application. Correct exception handling in your Web pages prevents sensitive exception details from being revealed to the user, improves application robustness,
and helps to avoid leaving your application in an inconsistent state in the event of an error.
When designing an exception management strategy, consider following guidelines:
- Do not use exceptions to control logic flow, and design your code to avoid exceptions where possible.
- Do not catch exceptions unless you can handle them.
- Centralize your exception handling solution.
- Design a global error handler to catch unhandled exceptions.
- Display user-friendly messages to end users.
- Do not reveal sensitive information through exception details.
- Design an appropriate exception propagation strategy.
- Design an appropriate exception logging strategy.
- Design an appropriate notification strategy for critical errors and exceptions.
- Design to log detailed exception information.
- Design your exception management system to remain secure in case of a failure.
Logging and Instrumentation
Designing an effective logging and instrumentation strategy is important for the security and reliability of your application. You should audit and log activity across the tiers of your application. These logs can be used to detect suspicious activity, which
frequently provides early indications of an attack on the system, and help to address the repudiation threat where users deny their actions. Log files may be required in legal proceedings to prove the wrongdoing of individuals. Generally, auditing is considered
most authoritative if the audits are generated at the precise time of resource access and by the same routines that access the resource.
When designing a logging and instrumentation strategy, consider following guidelines:
- Consider using platform features such as health monitoring to log and audit events.
- Centralize your logging and instrumentation mechanism.
- Consider auditing for user management events.
- Consider auditing for unusual activities.
- Consider auditing for business critical operations.
- Create secure log file management policies.
- Do not store sensitive information in the log or audit files.
Design your navigation strategy in a way that separates it from the processing logic. It should allow users to easily navigate through your screens or pages. Designing a consistent navigation structure for your application will help to minimize user confusion
as well as reducing the apparent complexity of the application.
When designing your navigation strategy, consider the following guidelines:
- Use well-known design patterns, such as MVC, to decouple the UI from the navigation logic where this logic is complex.
- Consider encapsulating navigation in a Master Page so that it is consistent across pages.
- Consider embedding navigation within user controls, especially working with smaller Web applications.
- When designing menus, consider using the .NET sitemap provider.
- Design a sitemap to help users to find pages on the site and allow search engines to crawl the site, if desired.
- Consider using wizards to implement navigation between forms in a predictable way.
- Consider hierarchical navigation for sites that are information-rich and are best organized as a large tree; for example, a library.
- Consider using visual elements such as embedded links, navigation menus, and breadcrumb text in the UI to help users understand where they are, what is available on the site, and how to navigate the site quickly.
- Consider designing to preserve navigation state.
Page Layout (UI)
Design your application so that the page layout can be separated from the specific UI components and UI processing. When choosing a layout strategy, consider whether designers or developers will be building the layout. If designers will be building the layout,
choose a layout approach that does not require coding or the use of development-focused tools.
When designing your layout strategy, consider the following guidelines:
- Evaluate cross-browser support requirements.
- Use Cascading Style Sheets (CSS) for layout whenever possible.
- Use table-based layout when you need to support a grid layout, but remember that table based layout can be slow to render, does not have full cross browser support, and there may be issues with complex layout.
- If you are displaying data in a grid or table format, use HTML tables to assist visually-impaired users and specialist user agents.
- Use a common layout for pages where possible to maximize accessibility and ease of use.
- Use Master Pages in ASP.NET applications to provide a common look and feel to all the pages.
- Avoid designing and developing large pages that accomplish multiple tasks, particularly where only a few tasks are usually executed with each request.
- Partition page content to improve caching efficiency and reduce rendering.
When designing for page rendering, you must ensure that you render the pages efficiently and maximize interface usability.
When designing a page rendering strategy, consider following guidelines:
- Consider minimizing the transmitted page size; for example, disable view state if it is not required.
- Consider data binding options. For example, you can bind custom objects or datasets to controls. However, be aware that binding only applies to rendered data in ASP.NET.
- Consider using AJAX for an improved user experience and better responsiveness.
- Consider using data paging techniques for large amounts of data to minimize scalability issues.
- Consider designing for globalization; for example, by using resource files for string data.
- Consider designing for localization in user interface components.
- Abstract the user process components from data rendering and acquisition functions.
Presentation entities store the data that you will use to manage the views in your presentation layer. Presentation entities are not always necessary. Consider using presentation entities only if the data sets are sufficiently large or complex that they must
be stored separately from the UI controls. Design or choose appropriate presentation entities that you can easily bind to user interface controls.
When designing presentation entities, consider the following guidelines:
- Determine if you need presentation entities.
- Consider using a custom class if you want to map controls directly to business entities.
- Consider the serialization requirements for your presentation entities.
- Avoid adding business logic to presentation entities.
- Consider implementing input data validation in your presentation entities.
- Consider using presentation entities to store state related to the user interface.
When designing a request processing strategy, you should ensure separation of concerns by implementing the request processing logic separately from the user interface.
When designing a request processing strategy, consider the following guidelines:
- Consider centralizing the common pre-processing and post-processing steps of Web page requests to promote logic reuse across pages. For example, consider creating a base class derived from the
Page class to contain your common pre- and post-processing logic.
- Consider dividing UI processing into three distinct roles, model, view, and controller/presenter, by using the MVC or MVP pattern.
- For improved testability, avoid the dependency between the view and model by using the Passive View pattern, which is a form of the MVP pattern.
- If you are designing views for handling large amounts of data, consider giving access to the model from the view using the Supervising Controller pattern, which is a form of the MVP pattern.
- If your application does not have a dependency on view state and you have a limited number of control events, consider using MVC pattern.
- If you have complex navigation and command processing requirements, consider using Front Controller pattern, which is a form of the MVC pattern.
- Do not implement any request processing logic in a view.
- Consider using the Intercepting Filter pattern to implement the processing steps as pluggable filters when appropriate.
- Consider using events to notify consumers of changes to state data; for example, by using the Observer pattern.
- Ensure that you do not mix business rules with the request processor logic.
When designing a Web application, an efficient and secure session management strategy is important for performance and reliability. You must consider session management factors such as what to store, where to store it, and how long information will be kept.
When designing a session management strategy, consider the following guidelines
- Do not rely on client state management options.
- Choose an appropriate session state store, such as in-process, ASP.NET StateServer, or a SQL Server database.
- If you have a single Web server, require optimum session state performance, and have a relatively limited number of concurrent sessions, use the in-process state store.
- If you have a single Web server, your sessions are expensive to rebuild, and you require durability in the event of an ASP.NET restart, use the session state service running on the local Web server.
- Use the SQL Server state store when reliability is your primary concern.
- Use a remote session state service or the SQL Server state store for Web farm scenarios.
- Protect your session state communication channel.
- Restrict access to session state data.
- Prefer basic types for session data to reduce serialization costs.
- Use the platform features to encrypt the session ID in your cookies.
- If cookies may be disabled in client browsers, use cookie-less sessions
Designing an effective validation solution is important for the security and reliability of your application. Improper or weak authorization can leave your application vulnerable to cross-site scripting attacks, SQL injection attacks, buffer overflows, and
other types of input attack.
When designing a validation strategy, consider following guidelines:
- Identify trust boundaries within Web application layers, and validate all data crossing these boundaries.
- Assume that all client-controlled data is malicious.
- Design your validation strategy to constrain, reject, and sanitize malicious values.
- Design to validate input for length, range, format, and type.
- Design to validate input from all sources, such as the query string, cookies, and HTML controls.
- Do not rely solely on ASP.NET request validation.
- Consider using the ASP.NET validation controls
- Use regular expressions to constrain input in ASP.NET
- Do not echo un-trusted input.
- If you need to write out un-trusted data, HTML-encode the output.
- Use client side validation for user experience, and server side validation for security.
- Avoid user-supplied file path and name input.
Presentation Layer Considerations
The presentation layer of your Web application to displays the user interface and facilitates user interaction. The design should focus on separation of concerns, where the user interaction logic is decoupled from the user interface components.
When designing the presentation layer, consider following guidelines:
- Consider separating the user interface components from the user interface process components.
- Evaluate how the presentation layer will interact with the business and data access layers.
- Design an input data validation strategy for the client (if appropriate) and for the server.
- Design a strategy for formatting data and displaying it, including visual styling, to the user.
- Use page output caching or fragment caching to cache static pages or parts of pages.
- Use the Observer pattern to handle user events.
- Use the Page Controller pattern to separate the business logic (controller) from the presentation logic (view).
- Use the Front Controller pattern when you have complex page navigation logic that can be configured dynamically.
- Use Web server controls if you need to compile these controls into an assembly for reuse across applications, or if you need to add additional features to existing server controls.
- Use Web user controls if you need to reuse UI fragments on several pages, or if you want to cache specific part of the page.
Business Layer Considerations
When designing the business layer for your Web application, consider how to implement the business logic and long-running workflows. Design business entities that represent the real world data, and use these to pass data between components.
When designing the business layer, consider following guidelines:
- Design a separate business layer that implements the business logic and workflows. This improves maintainability and testability of your application.
- Consider centralizing and re-using common business logic functions.
- Design your business layer to be stateless. This helps to reduce resource contention and increase performance.
- Design coarse-grained packages for data (business entities), such as Data Transfer Objects (DTOs).
- Design business components to be highly cohesive and loosely coupled.
- Design transactions for business critical operations.
- Determine whether to execute the process steps in a workflow synchronously or asynchronously.
Data Layer Considerations
Design a data layer for your Web application to abstract the logic necessary to access the database. Using a separate data layer makes the application easier to configure and maintain. The data layer may also need to access external service using service agents.
When designing the data layer, consider following guidelines:
- Design a separate data layer to hide the details of the database from other layers of the application.
- Design entity objects to interact with other layers, and to pass the data between them.
- Choose a data access technology that is appropriate for the type of data store.
- Design to take advantage of connection pooling to minimize the number of open connections.
- Design an exception handling strategy to handle data access errors, and to propagate exceptions to business layers.
- Consider using batch operations to reduce round trips to the database.
Service Layer Considerations
Consider designing a separate service layer if you plan to deploy your business layer on a remote tier, or if you plan to expose your business logic using Web service.
When designing the service layer, consider following guidelines:
- Design coarse-grained service methods to minimize the number of client-server interactions, and to provide loose coupling.
- Do not assume a specific client type will access the services.
- Design the services to be idempotent.
You should identify your performance objectives early in the design phase of a Web application by gathering the non-functional requirements. Response time, throughput, CPU, memory, and disk I/O are few of the key factors you should consider while designing
Consider the following guidelines for performance:
- Ensure the performance requirements are specific, realistic and flexible.
- Use non-distributed deployment to maximize performance.
- Implement caching techniques to improve the performance and scalability of the application.
- Perform batch operations to minimize the round trips across boundaries.
- Avoid initiating or participating in atomic transactions in the presentation layer as this reduces scalability.
- Store session information using the in-process approach.
- Reduce the volume of HTML transferred between server and client.
- Avoid unnecessary round trips over the network.
Security is an important consideration for protecting the integrity and privacy of the data and the resources of your Web application. You should design a security strategy for your Web application that uses tested and proven security solutions, and implement
authentication, authorization, and data validation to protect your application from a range of threats.
Consider the following guidelines for security:
- Consider the use of authentication at every trust boundary.
- Consider implementing a strong authorization mechanism to restrict resource access and protect business logic.
- Consider the use of input and data validation at every trust boundary to mitigate security threats such as cross-site scripting and code-injection.
- Do not rely on only client-side validation.
- Consider encrypting and digitally signing any sensitive data that is sent across the network.
When deploying a Web application, you should take into account how layer and component location will affect the performance, scalability and security of the application. You may also need to consider design trade-offs. Use either a distributed or a non-distributed
deployment approach, depending on the business requirements and infrastructure constraints.
Consider the following guidelines for deployment:
- Consider using non-distributed deployment to maximize performance.
- Consider using distributed deployment to achieve better scalability and to allow each layer to be secured separately.
In a non-distributed deployment scenario, all the logically-separated layers of the Web application are physically located on the same Web server, except for the database. You must consider how the application will handle multiple concurrent users, and how
to secure the layers that reside on the same server.
Consider the following guidelines:
- Consider using non-distributed deployment if you are not sharing your business logic with other applications.
- Consider using non-distributed deployment if your Web application is performance sensitive, because the local calls to other layers provide performance gains.
- Consider designing a component-based interface for your business layer.
- If your business logic runs in the same process, avoid authentication at the business layer.
- Consider using a trusted identity (through the trusted subsystem model) to access the database. This improves the performance and scalability of your application.
- Consider encrypting and digitally signing sensitive data passed between the Web server and database server.
In a distributed deployment, the presentation and business layers of the Web application reside on separate physical tiers, and communicate remotely. You will typically locate your business and data access layers on the same sever.
Consider the following guidelines when choosing a distributed deployment:
- Do not physically separate your business logic components unless this is necessary.
- If your business logic is shared by other applications, consider distributed deployment.
- If your security concerns prohibit you from deploying your business logic on your front-end Web server, consider distributed deployment.
- Consider the use of a firewall between the presentation layer and the business layer for additional security.
- Design the presentation layer such that it does not initiate, participate in, or vote on atomic transactions.
- Consider using a message-based interface for your business layer.
- Consider using the TCP protocol to communicate with business layer for best performance.
- Consider protecting sensitive data passed between different physical tiers.
- If the business layer is also accessed by other applications, consider using authentication in business layer..
When you deploy your Web application on multiple servers, you can use load balancing to distribute requests so that they are handled by different Web servers. This helps to maximize response times, resource utilization, and throughput.
Consider the following guidelines when designing your Web application to use load balancing:
- Avoid server affinity when designing scalable Web applications. Server affinity occurs when all requests from a particular client must be handled by the same server. It usually occurs when you use locally updatable caches, or in-process or local session
- Consider designing stateless components for your Web application; for example, a Web front end that has no in-process state and no stateful business components.
- Consider using Windows Network Load Balancing (NLB) as a software solution to implement redirection of requests to the servers in an application farm.
Web Farm Considerations
A Web farm allows you to scale out you application, which can also minimize the impact of hardware failures. When you add more servers, you can use either a load balancing or a clustering approach.
Consider the following guidelines:
- Consider using clustering to minimize the impact of hardware failures.
- Consider partitioning your database across multiple database servers if your application has high input/output requirements.
- Consider configuring the Web farm to route all requests from the same user to the same server to provide affinity where this is required.
- Do not use in-process session management in a Web farm when requests from the same user cannot be guaranteed to be routed to the same server. Use an out-of-process state server service or a database server for this scenario.
|Authentication and Authorization
||Federated Authentication (Single Sign On or SSO)
|Logging and Instrumentation
||Model View Presenter
||Model View Controller
||Two Step View
- Composite View - Combine individual views into a composite representation.
- Exception Shielding - Filter exception data that should not be exposed to external systems or users.
- Front Controller - Consolidate handling of all requests by channeling them through a single handler object, which can be modified at runtime with decorators.
- Model View Controller - Separate the user interface, the data repository features, and the code logic that binds the two together.
- Model View Presenter - Separate the user interface, the data repository features, and the code logic that binds the two together.
- Page Cache - Use a page cache to improve the response time for dynamic Web pages that are accessed frequently, but change less often and consume a large amount of system resources to construct.
- Page Controller - Accept input from the page request, and handle requests for a specific page or action on a Web site.
- Template View - Implement a common template view, and derive or construct views using the template view.
On the Microsoft platform, from an ASP.NET standpoint, you can combine the ASP.NET Web Forms model with a range of other technologies, including ASP.NET AJAX, ASP.NET MVC, Silverlight, and ASP.NET Dynamic Data:
- If you are designing connected Web applications that are exposed through a Web browser, consider using ASP.NET Web Forms.
- If you are designing connected Web applications that require increased interactivity or background processing, consider using ASP.NET AJAX.
- If you are designing connected Web applications that include islands of rich media content and interactivity, consider using Silverlight.
- If you are designing Web applications that implement a control-centric model with separate controllers and improved testability, consider using ASP.NET MVC.
- If you are designing Web applications for fast data-oriented development, consider using ASP.NET Dynamic Data.
patterns & practices Solution Assets