So far you've been reading how to manage state for a web application using various techniques. You've seen how to manage application state using the Application object, and you've seen how to manage both in- and out-of-process session state using the Session object and the available session state providers. What hasn't been discussed is how all of this is impacted when your application is running in a web farm.
Web farms are a topic that don't seem to get enough coverage in printed material, and people are unfortunately forced to learn how to code in a farm environment the hard way: write code, watch it break, rewrite the code.
A web farm is an environment in which multiple servers are all running copies of the same application. Windows software or special routers are used to distribute requests for a page between the different servers either for load balancing or to provide failover support in case a server goes down.
Three types of state need to be addressed within a web farm: application state, session state, and view state.
Using Application State in Web Farms
When you access the Application object, you are doing so at the AppDomain scope. Applications running on other servers will be running within different AppDomains. This means that when one server accesses the Application object, it is not accessing the same data as the other servers.
You can get around this in several ways. The first and easiest method is to simply avoid using the Application object's dictionary for storing data. If your design doesn't allow for storing application-wide data in this object, no additional coding is required to make your application "state safe" in a web farm.
A rule I live by is: "Statelessness is next to godliness." In large-scale enterprise applications, the maintenance of state decreases the rate at which the application can scale, and often introduces huge problems with performance and design. If you find yourself having to graph out state changes just to keep up, you may need to take another look at your design. As a rule, if you can avoid requiring state at all, your large-scale enterprise design will thank you for it.
If you absolutely have to have application-wide state storage, and you can't accomplish that using the database, you can create a web service hosted by a designated server in your farm that exposes central state management at the application level. You can also do this using a business object and a Singleton Remoting server. Web services are covered in Chapter 32, "Exposing Functionality with Web Services," and Remoting is covered in Chapter 41, "Remoting." The Web Services and Remoting options should be considered a last resort if you need application state in your web farm and can't accomplish it using a database.
Using Session State in Web Farms
Session state is far easier to scale from the single-server environment to a web farm environment. As you saw earlier in this chapter, you can use the ASP.NET State Server service or SQL Server as an out-of-process session state manager. Because session state is being managed outside the AppDomain scope of a single application, session state can be easily shared among all the applications participating in a single farm.
All the usual session state caveats apply here: Keep the data stored in the session small, consistently serializable, and pertinent. In this context, "pertinent" means that you should make sure that you need to store that information in session state, and that the information stored in the session is not duplicated anywhere else. For example, don't bother storing the user's authenticated name in session because it is already available in the User.Identity.Name property.
Using View State in Web Farms
Part of the overhead involved in view state that makes this author strongly recommend against its overuse is that view state is tamper-proof. This means that, by default, someone cannot send artificial view state to a page, nor can they take view state that originated on one server and send it to another.
This presents a problem in a web farm because view state is validated based on the server from which it originated. If a user requests a page from ServerA and then clicks a button on that page, it is highly likely that the resulting postback request could be sent to the same page on ServerB. To fix this problem, you can use the Web.config file to specify the validation settings for view state as well as keys used in the encryption of view state. If all servers are using the same keys to work with view state, all servers in the farm can read view state generated by any other server in the farm.
In addition to the hash validation of view state that prevents tamper proofing, view state can be encrypted if you will be posting back sensitive information. There are a variety of publicly available tools that will decode unencrypted view state and show you all the data contained within. If you have sensitive information stored in view state that needs to be posted back over a non-SSL request, you can encrypt view state.
This problem is corrected for web farms by using the <machineKey> element in Web.config. By default, this element is configured to allow the server to automatically generate its own key pair and to use SHA1 for the hashing algorithm used to verify view state. It can also be used to encrypt other things that you will see later in the book, such as the forms authentication ticket and the Role authorization cookie.
You will want to supply manually generated values for the validationKey and decryptionKey attributes of the <machineKey> element, and share those values among all servers in your web farm for proper operation. You can either create these keys on your own, or you can use the RNGCryptoServiceProvider (cryptographically sound random number generation) to build the keys. Three different types of hash validation can be performed on view state: SHA1, AES, and 3DES (Triple DES). For more information on how to use these and other cryptographic techniques, refer to Chapter 15, "Cryptography and Data Protection." To build cryptographically random keys, you should use the following Microsoft-recommended key sizes:
A sample Web.config file configured properly for a web farm might contain the following elements inside the <system.web> element:
<pages enableViewStateMac="true" viewStateEncryptionMode="Always" /> <machineKey validation="SHA1" validationKey="..." decryptionKey="..." />
With these elements in place, all servers in a web farm will both validate and encrypt view state data using the same validation algorithm and the same keys. This allows view state from the same page on different servers to function properly in a web farm environment.