Web Application Archetype
J.D. Meier, Alex Homer, David Hill, Jason Taylor, Prashant Bansode, Lonnie Wall, Rob Boucher Jr, Akshay Bogawat
- Define a Web application.
- Learn the general design considerations for a Web application.
- Learn the guidelines for key attributes of a Web application.
- Learn the guidelines for layers within a Web application.
- Learn the guidelines for performance, security, and deployment.
- Learn the key patterns and technology considerations.
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. Figure 1 illustrates a common Web application architecture with common components grouped by different areas of concern. Figure 1 A common Web application architecture
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, high-performance application.
When designing your Web application, consider the following guidelines:
- Partition your application logically. Use layering to partition your application logically 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 activities across the layers and 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 sensitive data in plain text across the 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 Secure Sockets Layer (SSL) encryption.
- Design your Web application to run using a least-privileged 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 damage.
Web Application Frame
There are several common issues that you must consider as you develop your design. These issues can be categorized into specific areas of the design. The following table lists the common issues for each category where mistakes are most often made.
|Category ||Key issues|
|Authentication ||Lack of authentication across trust boundaries |
| ||Storing passwords in a database as plain text |
| ||Designing custom authentication mechanism instead of using built-in capabilities |
|Authorization ||Lack of authorization across trust boundaries |
| ||Incorrect role granularity |
| ||Using impersonation and delegation when not required |
|Caching ||Caching volatile data |
| ||Not considering caching page output |
| ||Caching sensitive data |
| ||Failing to cache data in a ready-to-use format |
|Exception Management ||Revealing sensitive information to the end user |
| ||Not logging sufficient details about the exception |
| ||Using exceptions to control application flow |
|Logging and Instrumentation ||Failing to implement adequate instrumentation in all layers |
| ||Failing to log system-critical and business-critical events |
| ||Not supporting run-time configuration of logging and instrumentation |
| ||Logging sensitive information |
|Navigation ||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 |
|Page Rendering ||Using post backs and page refreshes for many user interactions |
| ||Using excessive page sizes that reduce performance |
|Presentation Entity ||Creating custom entity objects when not required |
| ||Adding business logic to presentation entities |
|Request Processing ||Mixing processing and rendering logic |
| ||Choosing an inappropriate pattern |
|Service Interface ||Breaking the service interface |
| ||Implementing business rules in a service interface |
| ||Failing to consider interoperability requirements |
|Session Management ||Using an incorrect session store |
| ||Not considering serialization requirements |
| ||Not persisting session data when required |
|Validation ||Failure to implement server-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 of attack.
Consider the following guidelines when designing an authentication strategy:
- 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, such as the forms element, when possible.
- Enforce strong account management practices such as account lockouts and expirations.
- Enforce strong password policies. This includes specifying password length and complexity, and password expiration policies.
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.
Consider the following guidelines when designing an authorization strategy:
- Identify trust boundaries within the Web application layers and authorize users across trust boundaries.
- Use URL authorization for page and directory access control.
- Consider the granularity of your authorization settings. Building your authorization with too much granularity will increase your management overhead; however, using too much granularity will reduce flexibility.
- Access downstream resources using a trusted identity based on the trusted subsystem 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 first decide when to load data into the cache. Try to load cache data asynchronously or by using a batch process to avoid client delays.
Consider the following guidelines when designing caching:
- 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.
- Pool shared resources that are expensive, such as network connections, instead of caching them.
- Cache data in a ready-to-use format.
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.
Consider the following guidelines when designing an exception management strategy:
- Do not use exceptions to control the logical flow of your application.
- Do not catch exceptions unless you must handle them, you need to strip sensitive information, or you need to add additional information to the exception.
- Design a global error handler to catch unhandled exceptions.
- Display user-friendly messages to end users whenever an error or exception occurs.
- Do not reveal sensitive information, such as passwords, through exception details.
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.
Consider the following guidelines when designing a logging and instrumentation strategy:
- Consider auditing for user management events.
- Consider auditing for unusual activities.
- Consider auditing for business-critical operations.
- Create secure log file management policies, such as restricting the access to log files, allowing only write access to users, etc.
- 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. Your strategy should allow users to navigate easily through your screens or pages. Designing a consistent navigation structure for your application will help to minimize user confusion as well as reduce the apparent complexity of the application.
Consider the following guidelines when designing your navigation strategy:
- Use well-known design patterns, such as Model-View-Presenter (MVP), to decouple UI processing from output rendering.
- Consider encapsulating navigation in a master page so that it is consistent across pages.
- Design a site map to help users find pages on the site, and to allow search engines to crawl the site if desired.
- Consider using wizards to implement navigation between forms in a predictable way.
- Consider using visual elements such as embedded links, navigation menus, and breadcrumb navigation in the UI to help users understand where they are, what is available on the site, and how to navigate the site quickly.
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.
Consider the following guidelines when designing your layout strategy:
- 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.
- 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 for all of the pages.
- Avoid designing and developing large pages that accomplish multiple tasks, particularly where only a few tasks are usually executed with each request.
When designing for page rendering, you must ensure that you render the pages efficiently and maximize interface usability.
Consider the following guidelines when designing a page-rendering strategy:
- 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 data-paging techniques for large amounts of data to minimize scalability issues.
- Consider designing to support localization in UI 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 datasets 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 UI controls.
Consider the following guidelines when designing presentation entities:
- Determine if you need presentation entities. Typically, you might need presentation entities if the data or data format to be displayed is specific to the presentation layer.
- Consider the serialization requirements for your presentation entities, if they are to be passed across the network or stored on the disk.
- Consider implementing data type validation in the property setters of your presentation entities.
- Consider using presentation entities to store state related to the UI. If you want to use this state to help your application recover from a crash, make sure after recovery that the user interface is in a consistent state.
When designing a request-processing strategy, you should ensure separation of concerns by implementing the request-processing logic separately from the UI.
Consider the following guidelines when designing a request-processing strategy:
- 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 ASP.NET 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 Model-View-Controller (MVC) or Model-View-Presenter (MVP) pattern.
- If you are designing views for handling large amounts of data, consider giving access to the model from the view by 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 the MVC pattern.
- Consider using the Intercepting Filter pattern to implement the processing steps as pluggable filters when appropriate.
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.
Consider the following guidelines when designing a session-management strategy:
- 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 a remote session state service or the Microsoft SQL Server® state store for Web farm scenarios.
- If you are storing state on a separate server, protect your session state communication channel.
- Prefer basic types for session data to reduce serialization costs.
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.
Consider the following guidelines when designing a validation strategy:
- Identify trust boundaries within Web application layers, and validate all data crossing these boundaries.
- Assume that all client-controlled data is malicious and needs to be validated.
- Design your validation strategy to constrain, reject, and sanitize malicious input.
- Design to validate input for length, range, format, and type.
- Use client-side validation for user experience, and server-side validation for security.
Presentation Layer Considerations
The presentation layer of your Web application displays the UI and facilitates user interaction. The design should focus on separation of concerns, where the user interaction logic is decoupled from the UI components.
Consider the following guidelines when designing the presentation layer:
- Consider separating the UI components from the UI process components.
- Use client-side validation to improve user experience and responsiveness, and server-side validation for security. Do not rely on just client-side validation.
- Use page output caching or fragment caching to cache static pages or parts of pages.
- 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 a specific parts 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.
Consider the following guidelines when designing the business layer:
- Design a separate business layer that implements the business logic and workflows. This improves the maintainability and testability of your application.
- Consider centralizing and reusing common business logic functions.
- Design your business layer to be stateless. This helps to reduce resource contention and increase performance.
- Use a message-based interface for the business layer. This works well with a stateless Web application business layer.
- Design transactions for business-critical operations.
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 services using service agents.
Consider the following guidelines when designing the data layer:
- 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.
- 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 a Web service.
Consider the following guidelines when designing the service layer:
- If your business layer is on a remote tier, design coarse-grained service methods to minimize the number of client-server interactions, and to provide loose coupling.
- Design the services without assuming a specific client type.
- Design the services to be idempotent, assuming that the same message request may arrive multiple times.
Testing and Testability Considerations
is a measure of how well your system or components allow you to create test criteria and execute tests to determine if the criteria are met. You should consider testability when designing your architecture because it makes it easier to diagnose problems earlier and reduce maintenance cost. To improve the testability of your application, you can use logging events, provide monitoring resources, and implement test interfaces.
Consider the following guidelines for testability:
- Clearly define the inputs and outputs of the application or components during the design phase.
- Consider using the Passive View pattern (a variation of the MVP pattern) in the presentation layer, which removes the dependency between the view and the model.
- Design a separate business layer to implement the business logic and workflows, which improves the testability of your application.
- Design an effective logging strategy, which allows you to detect bugs that might otherwise be difficult to discover. Logging will help you to focus on faulty code when bugs are found. Log files should contain information that can be used to replicate the issues.
- Design loosely coupled components that can be tested individually.
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 a few of the key factors you should consider when designing your application.
Consider the following guidelines for performance:
- Ensure that the performance requirements are specific, realistic, and flexible.
- Implement caching techniques to improve the performance and scalability of the application.
- Perform batch operations to minimize round trips across boundaries.
- Reduce the volume of HTML transferred between server and client. For instance, you can disable view state when you do not need it; limit the use of graphics, and considering using compressed graphics where appropriate.
- 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 validation and data validation at every trust boundary to mitigate security threats such as cross-site scripting and code-injection.
- Do not rely on client-side validation only. Use server-side validation as well.
- 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 might 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 separate 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. Figure 2 shows this scenario. Figure 2 Non-distributed deployment of a Web application
Consider the following guidelines when choosing a non-distributed deployment:
- 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 scenario, 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. Figure 3 shows this scenario. Figure 3 Distributed deployment of a Web application
Consider the following guidelines when choosing a distributed deployment:
- Do not physically separate your business logic components unless this is necessary.
- If your security concerns prohibit you from deploying your business logic on your front-end Web server, consider distributed deployment.
- Consider using a message-based interface for your business layer.
- Consider using the TCP protocol with binary encoding to communicate with the business layer for best performance.
- Consider protecting sensitive data passed between different physical tiers.
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. Figure 4 shows this scenario. Figure 4 Load balancing a Web application
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 state stores.
- 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 your application, which can also minimize the impact of hardware failures. When you add more servers, you can use either a load-balancing or clustering approach.
Consider the following guidelines when designing your Web application to use a Web farm:
- 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 in order 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.
|Category ||Relevant patterns|
|Caching ||Cache Dependency |
| ||Page Cache |
|Exception Management ||Exception Shielding |
|Logging and Instrumentation ||Provider |
|Navigation ||Model-View-Presenter |
| ||Model-View-Controller |
|Page Layout (UI) ||Template View |
| ||Composite View |
| ||Transform View |
| ||Two-Step View |
|Request Processing ||Intercepting Filter |
| ||Page Controller |
| ||Front Controller |
| ||Passive View |
| ||Supervising Controller |
|Service Interface Layer ||Façade |
| ||Service Interface |
- Cache Dependency. Use external information to determine the state of data stored in a cache.
- Composite View. Combine individual views into a composite representation.
- Exception Shielding. Filter exception data that should not be exposed to external systems or users.
- Façade. Implement a unified interface to a set of operations to provide a simplified, reduced coupling between systems.
- Front Controller. Consolidate request handling by channeling all requests through a single handler object, which can be modified at run time with decorators.
- Intercepting Filter. Create a chain of composable filters (independent modules) to implement common pre-processing and post-processing tasks during a Web page request.
- Model-View-Controller. Separate the UI code into three separate units: Model (data), View (interface), and Presenter (processing logic), with a focus on the View. Two variations on this pattern include Passive View and Supervising Controller, which define how the View interacts with the Model.
- Model-View-Presenter. Separate request processing into three separate roles, with the View being responsible for handling user input and passing control to a Presenter object.
- Page Cache. 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 request and handle it for a specific page or action on a Web site.
- Passive View. Reduce the view to the absolute minimum by allowing the controller to process user input and maintain the responsibility for updating the view.
- Provider. Implement a component that exposes an API that is different from the client API, to allow any custom implementation to be seamlessly plugged in.
- Service Interface. A programmatic interface that other systems can use to interact with the service.
- Supervising Controller. A variation of the MVC pattern in which the controller handles complex logic, in particular coordinating between views, but where the view is responsible for simple view-specific logic.
- Template View. Implement a common template view, and derive or construct views using this template view.
- Transform View. Transform the data passed to the presentation tier into HTML to be displayed on the UI.
- 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.
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, Microsoft Silverlight™, and ASP.NET Dynamic Data. Consider the following guidelines:
- If you want to build applications that are accessed through a Web browser or specialized user agent, consider using ASP.NET.
- If you want to build applications that provide increased interactivity and background processing, with fewer page reloads, consider using ASP.NET with AJAX.
- If you want to build applications that include rich media content and interactivity, consider using ASP.NET with Silverlight controls.
- If you are using ASP.NET, consider using master pages to implement a consistent UI across all pages.
- If you are building a data-driven Web application with pages based on the data model of the underlying database, consider using ASP.NET Dynamic Data.