Designing and Developing Web Applications Using Microsoft .NET Framework 4: Designing the Application Architecture
- By Tony Northrup
- Objective 1.1: Plan the Division of Application Logic
- Objective 1.2: Analyze Requirements and Recommend a System Topology
- Objective 1.3: Choose Appropriate Client-Side Technologies
- Objective 1.4: Choose Appropriate Server-Side Technologies
- Objective 1.5: Design State Management
- Chapter Summary
Objective 1.2: Analyze Requirements and Recommend a System Topology
Large-scale Internet and intranet applications require you to create a logical design, map it to a physical server architecture, and choose how the different layers will interact. This objective includes an overview of common system topologies, describes how to select a binding for interapplication interactions, helps you choose a binding type, and provides best practices for cross-cutting concerns.
Designing a System Topology
There are two system topologies with which you should be familiar: MVC (as described in Objective 1.1: Plan the Division of Application Logic), and the three-tier architecture. The three-tier architecture consists of the following:
Presentation. The user interface. This tier is responsible for layout and formatting.
Application Logic. Also known as Business Logic, this tier is responsible for making decisions based on business rules. If this tier has multiple layers, you can refer to the architecture as an n-tier architecture.
Data. Typically implemented by a database, this tier is responsible for storing and retrieving information.
For a typical ASP.NET web application, the three-tier architecture might be implemented as follows:
Presentation. An IIS web server with an ASP.NET web application. The web application retrieves data from the logic tier by using Windows Communication Foundation (WCF), performs minor formatting and processing, adds it to a webpage, and returns it to the client’s web browser.
Application Logic. A .NET Framework application exposing interfaces via WCF. The logic tier receives requests from the presentation tier, such as “How long will it take to ship this item?” or “Should I offer this customer a coupon?” The logic tier retrieves all data required to answer queries from the data tier.
Data. A database server, such as Microsoft SQL Server. The data tier stores raw data, such as a table containing every item for sale and the number of items in inventory or a table with every customer and an index of their orders.
Whether you implement an MVC architecture, a three-tier architecture, or an n-tier architecture, you benefit from these advantages:
Easier to divide among different developers. Let the database guys write the logic tier and the design guys write the presentation tier.
Easier to replace a single component. For example, you could use existing Linux web servers for the initial deployment and later migrate to Windows. By separating the presentation layer, you would not have to rewrite the entire application—just the presentation.
Easier to scale. You can add more web servers without making any changes to the presentation layer.
More flexibility. Most web applications include logic and presentation in a single assembly. By separating the two, you simplify replacing the user interface. It also allows you to support multiple, different user interfaces, such as web, Microsoft Windows, and mobile interfaces.
Easier to test. The only way to create a reliable application is to create a testable application. As described in Objective 1.1: Plan the Division of Application Logic, providing SoC allows you to more easily test individual components.
If these three tiers aren’t familiar to you as a web developer, it is because most web applications use a two-tier logical architecture that combines presentation and logic into a single set of classes. Unless you go out of your way, ASP.NET applications (other than MVC applications) use a two-tier architecture.
Designing Interactions Between Applications
Modern web applications are rarely isolated to themselves. They query databases, web services, and other applications to retrieve the data they need. They also provide updates by initiating order processing and signaling support.
Whether the communications are between different applications or different tiers within a single application, you should use WCF to implement it. WCF provides a powerful, flexible, and (optionally) standards-based way to communicate between processes, either on the same computer or across the network.
WCF supports many types of network protocols, implemented as bindings. If you need to be able to communicate across the Internet, choose one of the following HTTP bindings because HTTP communications are almost always allowed through firewalls:
wsHttpBinding. A standards, SOAP-based web service, wsHttpBinding is perfect when you will be communicating with .NET Framework–based hosts or if you need to communicate across the Internet, where firewalls might block non-HTTP traffic. wsHttpBinding provides powerful security features, making it the binding type of choice for Internet communications. wsHttpBinding does not support streaming or duplex communications.
WSDualHttpBinding. Like wsHttpBinding, except it provides duplex communications when the service needs to initiate communications to a client. As discussed in Objective 1.1: Plan the Division of Application Logic, duplex communications will not work if the client is behind a firewall or Network Address Translation (NAT) device.
basicHttpBinding. Like wsHttpBinding, basicHttpBinding is SOAP-based. However, it is based on earlier SOAP 1.1 standards and does not include the full set of wsHttpBinding features, such as encryption. basicHttpBinding is primarily useful for communicating with WS-Basic Profile conformant web services, such as ASMX-based web services.
webHttpBinding. A REST-style binding that functions differently than SOAP. REST uses a wider variety of HTTP commands than SOAP, such as GET, PUT, and DELETE.
If you don’t need to communicate across firewalls or the public Internet, and all hosts are .NET Framework–based, you can choose from these more powerful bindings:
netNamedPipeBinding. The preferred binding type for communications between processes on a single computer.
netTcpBinding. The most powerful binding type when all hosts are based on the .NET Framework.
NetMsmqBinding. Useful when you need to queue messages for later processing. For example, the client might need to submit a task to a server that will not be able to process the message in a timely manner or is completely offline.
NetPeerTcpBinding. Provides peer-to-peer communications when more than two hosts are involved.
Use the flowchart in Figure 1-4 to choose a binding type for your scenario. Although the flowchart does not include all binding types, it does cover the most common uses.
Figure 1-4 . WCF binding decision flowchart
Any service you expose can use multiple bindings. Therefore, you can provide a binding based on netTcpBinding for .NET Framework–based hosts and a second wsHttpBinding for hosts that use open standards.
Although choosing the binding type is an important decision, it’s relatively easy to change after the fact. Choose to define both the client and server bindings using configuration files, rather than hard-coding them into your application. Rely on discover protocols, such as Web Service Definition Language (WSDL), to save yourself from reconfiguring clients if the server settings change.
When designing interactions between applications, consider whether your interactions will be chatty or chunky:
Chatty application communications create many small requests. Chatty applications perform well when latency (the time it takes to send a message across the network) is low.
Chunky application communications create fewer large requests. Chunky applications perform well when bandwidth (the total amount of data that can be sent across the network) is high.
Choose to bundle your communications together into chunks when the network infrastructure is high-latency and high-bandwidth, such as satellite or inter-continental communications. Use chatty communications by sending smaller messages immediately when the network infrastructure is low-latency and low-bandwidth, such as communications with mobile devices. The difference will be insignificant on most local area networks (LANs), which are low-latency and high-bandwidth.
Mapping the Logical Design to the Physical Implementation
After you have divided your application into layers to create your application’s logical architecture, you need to design the physical architecture. The physical architecture defines the number of servers you will host the application on and how they are interconnected. At a high level, there are two different physical architecture philosophies:
Separate everything. Place the web server, application server, and database servers on different computers. This approach provides greater scalability.
Combine everything. Place all services on a single server. For the same cost, this approach provides better performance, reliability, and manageability.
Having a multitier logical architecture does not require you to deploy the same physical architecture. As Figure 1-5 illustrates, you can deploy all three logical layers to a single physical computer. Alternatively, you can deploy each layer to its own computer. You also have the option of deploying two layers to a single server, or of deploying ten web servers, three application servers, and a database cluster—the combinations are endless.
Figure 1-5. Single server vs. multiple servers for a three-tier web application
The physical architecture you choose depends on several factors. The single-server architecture has the following benefits:
Up-front costs. Obviously, if you deploy an application to three servers, you have to buy more hardware. This factor can be eliminated by using virtualization software, such as Hyper-V, and creating virtual machines for each server instance. You also need more operating system licenses. However, you might be able to use a less-expensive operating system for the web server, such as Windows Server 2008 R2 Web Edition. Instead of dividing your hardware and software budget across multiple servers, you can put the same money into a single server and achieve much better performance.
Management costs. The more computers you have, the more you need to manage. Over time, management costs typically exceed up-front costs.
Complexity. Simple is always superior. The more servers you add, the more complex your configuration will be.
Reliability. Each server you add to a web application is another component that can fail. If you deploy a three-tier application to three different servers, each server becomes a single point of failure; a failure of any one of the three servers would take the application offline. Similarly, scheduled downtime for any of the three servers requires scheduled downtime for the entire application. Additionally, communications between the servers becomes another single point of failure. If the network link between the servers fails, the entire application fails. You can use redundancy to overcome the decreased reliability of a multiple-server architecture, but your up-front and management costs will go up proportionately.
Efficient interprocess communications. Communicating across a network, even a LAN, always introduces some latency. It will always be faster for the web, logic, and data tiers to communicate when they are located on the same server.
The multiple-server architecture provides these benefits:
Scalability. With modern computing power, all but the busiest public web applications can be hosted on a single server. If your application requires more processing time or memory than a single computer can provide, dividing different tiers between physical computers can alleviate that concern.
Isolation. Deploying a tier to a separate physical computers guarantees that the load on other tiers will not affect that tier’s performance. For example, if you are concerned that a denial-of-service attack might cause IIS to consume 100 percent of the server’s processing time, you can place the database on a separate physical computer to prevent the database from being affected. The hosted application is still inaccessible because of the load on the web server, but if other applications share the same database, those applications are not affected (unless, of course, the denial-of-service attack caused the website to submit costly database queries).
Objective 6.3: Plan for Scalability and Reliability, in Chapter 6. "Designing a Deployment Strategy," provides more detail about how to meet quality of service (QoS) requirements.
Validating Nonfunctional Requirements and Cross-Cutting Concerns
Cross-cutting concerns and nonfunctional requirements are noncore functions that affect many parts of an application. For example, management, monitoring, logging, and authentication affect all parts of the application, but they are not part of the core functionality.
As a developer, you should strive to create applications that systems administrators can configure and manage without needing development experience. You can do this by following these best practices:
Read all configuration settings from XML files, such as the Web.config file. You can do this by using the ConfigurationManager.AppSettings property. Administrators should already be familiar with editing XML files, so storing commonly changed settings (such as the address of a server or number of seconds in a timeout) in the Web.config file allows administrators to change an application’s behavior without contacting the developer.
Store application settings in an external .config file. To allow an upgrade or re-installation to overwrite the Web.config file without affecting the application configuration, store application-specific settings in a separate XML file. You can reference this file by using the following syntax:
<configuration> <appSettings file="externalSettings.config"/> </configuration>
Never store constants in a code file. It might seem obvious not to store connection strings in a code file; however, you should also avoid storing the number of rows that appear on a page, the number of retries, or the path to a shared folder in a code file.
Use resource files. It’s often OK to store text, such as “OK” or “Cancel”, in an .aspx file. However, you should never store text that appears in a user interface in a code file. Instead, reference a resource file that administrators can edit without recompiling the application.
Disable debugging by default, but allow it to be re-enabled. Ideally, if a systems administrator cannot solve a problem, she describes it to the developer, who then re-creates the problem in a lab environment. In practice, however, some problems cannot easily be re-created, and you have no choice but to debug an application in the production environment. Plan for this by designing applications that allow debugging with proper authentication.
Allow back-ups. Generally, web applications can be backed up as regular files. However, you must ensure that the data store you use can be backed up. If you use a SQL Server database, ensure that administrators know which tables to back up, and how frequently to back them up. Avoid keeping files locked, which might prevent them from being backed up.
Start correctly after a reboot. Operations need to regularly restart servers. Although most web applications start automatically when the server comes back online, you should test your application to ensure that it functions properly after restarting either the web server, the database server, or both. In particular, avoid establishing database connections or reading important data in the Application.Start event, because the database server might be offline when the web server starts. A related trait to plan for is known as graceful degradation or resiliency, which allows the application to recover from a temporary network, database, or application server outage.
Plan for database changes. Table structure can change over time. For example, a future version of an application might add a column to a table. To provide forward-compatibility and ensure that different versions of your application can interact with a single database, refer to table columns using names rather than column numbers. This is handled automatically if you use Entity Data Modeling.
Document thoroughly. Naturally, you should comment both your code and configuration files. Additionally, you should write documentation for testing, deploying, configuring, monitoring, backing up, and restoring your application.
When you actually develop the application, avoid mixing functional and nonfunctional code. Instead, use the principals of aspect-oriented programming (AOP) and separate cross-cutting code into separate concerns.
Evaluating Baseline Needs
During the design phase, you need to evaluate the baseline needs of your web application. Don’t look too far into the future; instead, focus on what the application will need during the first six months. When the application is in production, you will be able to examine real-world performance factors and plan more accurately.
The following list describes the most important information you need to gather:
Uptime requirements. These requirements are often expressed as 99% (“two nines”), 99.9% (“three nines”), or 99.99% (“four nines”). You need to determine whether a single server can meet the uptime requirements, factoring in planned downtime caused by updates.
Responsiveness. How long users are willing to wait for a response from your server. With Internet applications, you must also factor in the network latency.
Peak number of simultaneous users. The number of users who will be logged on simultaneously.
Peak number of requests per second. The number of requests the web application will receive within a second. If this is less than one (as it is with most new web applications), you typically don’t have to worry about processor capabilities, as even low-end shared web servers will be able to process most requests in less than a second.
Estimating these values allows you to create baseline infrastructure requirements, such as the following:
Disk capacity. .NET Framework code typically takes very little disk space; however, databases can grow very large. Provide at least twice the estimated capacity of your data to allow for the inherent inefficiencies of database storage.
Number of processor cores. Provide enough processing power to render pages faster than the peak number of requests per second. If the server cannot keep up with this number, the web server will queue requests. Short-term queuing might still occur when an abnormally high number of requests arrives within a few seconds, but the temporarily reduced responsiveness is typically acceptable.
Memory. The amount of random access memory (RAM) your application will store. If you plan to store any large collections in memory rather than accessing them from a database, ensure the web server has at least twice that space available. The web server will use any excess memory for caching.
Bandwidth. You can estimate the bandwidth requirements by multiplying the peak number of requests per second by the average page size (including images and video). Rendered webpages consume very little bandwidth. Instead, most web bandwidth is consumed by transmitting images and video.
Number of servers. You might need multiple servers to provide redundancy to meet the uptime requirements. If you are planning for a high peak number of requests per second and a single server cannot provide the processing power, you might need multiple servers to meet your responsiveness requirement.
CDN needs. For Internet applications, verify that your Internet connection has sufficient available bandwidth to meet peak requirements. If it is insufficient, use a web hosting provider with sufficient bandwidth or distribute the images and video by using a CDN.
The two most commonly used system architectures are MVC (discussed in Objective 1.1: Plan the Division of Application Logic) and three-tier. The three-tier architecture creates an SoC between the presentation, application logic, and data tiers.
Unless you are required to work with a system that does not support it, you should use MFC to communicate between applications. MFC provides a wide variety of protocols to meet interoperability, performance, and queuing requirements.
When mapping logical design to physical implementation, use the minimum amount of servers required to meet your needs. Unless you need multiple servers for redundancy, scalability, or isolation, use a single server.
Cross-cutting concerns such as monitoring, logging, operations, and security are not related to the application’s core functionality. However, they contribute greatly to the manageability of the application. Whenever possible, use coding best practices that separate cross-cutting concerns into separate classes and store settings administrators might want to change separately from your code.
Although baseline needs must be estimated, they are important because you can use them to specify hardware requirements. Typically, you should err on the side of using less expensive hardware, but provide a convenient path to upgrade in the event the application has higher requirements after it is in production.
Answer the following questions to test your knowledge of the information in this objective. You can find the answers to these questions and explanations of why each answer choice is correct or incorrect in the Answers section at the end of this chapter.
You need to design a physical architecture to meet these requirements:
The website will remain online if the web server is restarted.
The database server will not be affected by a denial-of-service attack against the web server.
You must minimize hardware costs.
How many servers will you need?
You need to design a physical architecture to meet these requirements:
The website must be able to serve six requests per minute.
The database server will store 2 TB of data.
You must minimize hardware costs.
How many servers will you need?
You are designing a three-tier web application. You need to choose the method of communication between the web and application layers to meet these requirements:
The application server will use the .NET Framework 4.0.
The application server must be physically isolated.
The application server will be located on the same high-speed LAN as the web server and database servers.
The web server will be located behind a firewall.
The communications will be two-way.
The communications must be as efficient as possible.
Which WCF binding type will you use?
The new application is designed with a traditional three-tier architecture, as shown in Figure 1-6. Initially, all three layers will be implemented using a single server.
Figure 1-6 . A three-tier application for Margie’s Travel
Management wants to verify that the design meets its requirements. Answer the following question about the future performance of the application:
What changes will the company need to make to the application if it moves each tier to its own server?
What changes will the company need to make to the logic tier if it wants to create a Windows Presentation Foundation (WPF) application as a secondary presentation interface?
What changes will the company need to make if it replaces SQL Server 2008 R2 with a non-Microsoft database server?
What changes will the company need to make if it replaces the ASP.NET presentation interface with a Linux presentation interface? What impact will that have?
The company expects the website to get about 200 visitors per day. Will a single, dedicated server be fast enough?