ptg 1404 CHAPTER 29 Caching Application Pages and Data ConnectionString=”<%$ ConnectionStrings:Movies %>” SelectCommand=”SELECT Title, Director FROM Movies” Runat=”server” /> </div> </form> </body> </html> The page in Listing 29.42 includes an <%@ OutputCache %> directive with a SqlDependency attribute. The value of the SqlDependency attribute is the name of the database enabled for SQL dependencies in the web configuration file, followed by the name of a database table. If you open the page in Listing 29.42 in your browser and click your browser’s Reload button multiple times, you notice that the time displayed does not change. The page is output cached (see Figure 29.16). FIGURE 29.16 Using Page Output Caching with a Polling SQL cache dependency. However, if you modify the Movies database, the page is dropped from the cache auto- matically (within 5 seconds). The next time you click the Reload button, the modified data displays. If you want to make a page dependent on multiple database tables, you can assign a semi- colon-delimited list of database and table names to the SqlDependency attribute. From the Library of Wow! eBook ptg 1405 Using SQL Cache Dependencies 29 NOTE You also can use Polling SQL cache dependencies with a n <%@ OutputCache %> direc- tive included in a User Control. In other words, you can use Polling SQL cache depen- dencies with Partial Page Caching. Using Polling SQL Cache Dependencies with DataSource Caching You can use Polling SQL cache dependencies with both the SqlDataSource and ObjectDataSource controls by setting the SqlCacheDependency property. For example, the page in Listing 29.43 caches the output of a SqlDataSource control until the Movies data- base table is modified. LISTING 29.43 PollingSQLDataSourceCache.aspx <%@ Page Language=”C#” %> <!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”> <script runat=”server”> protected void srcMovies_Selecting(object sender, ➥SqlDataSourceSelectingEventArgs e) { lblMessage.Text = “Retrieving data from database”; } </script> <html xmlns=”http://www.w3.org/1999/xhtml” > <head id=”Head1” runat=”server”> <title>Polling SQL DataSource Cache</title> </head> <body> <form id=”form1” runat=”server”> <div> <asp:Label id=”lblMessage” EnableViewState=”false” Runat=”server” /> <hr /> <asp:GridView id=”grdMovies” DataSourceID=”srcMovies” Runat=”server” /> <asp:SqlDataSource From the Library of Wow! eBook ptg 1406 CHAPTER 29 Caching Application Pages and Data id=”srcMovies” ConnectionString=”<%$ ConnectionStrings:Movies %>” SelectCommand=”SELECT Title, Director FROM Movies” EnableCaching=”true” SqlCacheDependency=”MyDatabase:Movies” OnSelecting=”srcMovies_Selecting” Runat=”server” /> </div> </form> </body> </html> In Listing 29.43, the SqlDataSource control includes both an EnableCaching property and a SqlCacheDependency property. A database name and table name are assigned to the SqlCacheDependency property. (The database name must correspond to the database name configured in the <sqlCacheDependency> section of the web configuration file.) If you need to monitor multiple database tables, you can assign a semicolon-delimited list of database and table names to the SqlCacheDependency property. Using Polling SQL Cache Dependencies with Data Caching You also can use Polling SQL cache dependencies when working with the Cache object. You represent a Polling SQL cache dependency with the SqlCacheDependency object. For example, the page in Listing 29.44 creates a SqlCacheDependency object that represents the Movies database table. When a DataTable is added to the Cache object, the DataTable is added with the SqlCacheDependency object. LISTING 29.44 PollingSQLDataCache.aspx <%@ Page Language=”C#” Trace=”true” %> <%@ Import Namespace=”System.Data” %> <%@ Import Namespace=”System.Data.SqlClient” %> <%@ Import Namespace=”System.Web.Configuration” %> <!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”> <script runat=”server”> void Page_Load() { DataTable movies = (DataTable)Cache[“Movies”]; if (movies == null) { From the Library of Wow! eBook ptg 1407 Using SQL Cache Dependencies 29 movies = GetMoviesFromDB(); SqlCacheDependency sqlDepend = new SqlCacheDependency(“MyDatabase”, “Movies”); Cache.Insert(“Movies”, movies, sqlDepend); } grdMovies.DataSource = movies; grdMovies.DataBind(); } private DataTable GetMoviesFromDB() { Trace.Warn(“Retrieving data from database”); string conString = WebConfigurationManager.ConnectionStrings[“Movies”].ConnectionString; SqlDataAdapter dad = new SqlDataAdapter(“SELECT Title,Director FROM Movies”, conString); DataTable movies = new DataTable(); dad.Fill(movies); return movies; } </script> <html xmlns=”http://www.w3.org/1999/xhtml” > <head id=”Head1” runat=”server”> <title>Polling SQL Data Cache</title> </head> <body> <form id=”form1” runat=”server”> <div> <asp:GridView id=”grdMovies” Runat=”server” /> </div> </form> </body> </html> In Listing 29.44, an instance of the SqlCacheDependency class is created. A database name and table name are passed to the constructor for the SqlCacheDependency class. This class is used as a parameter with the Cache.Insert() method when the DataTable is added to the Cache. From the Library of Wow! eBook ptg 1408 CHAPTER 29 Caching Application Pages and Data NOTE If you need to create dependencies on multiple database tables, you need to create multiple SqlCacheDependency objects and represent the multiple dependencies with an instance of the AggregateCacheDependency class. Using Push SQL Cache Dependencies When using Microsoft SQL Server 2008 or Microsoft SQL Server 2005, you have the option of using Push SQL cache dependencies rather than Polling SQL cache dependencies. These databases include a feature called query notifications, which uses the Microsoft SQL Server Service Broker in the background. The Service Broker can automatically send a message to an application when data changes in the database. WARNING You can create two types of databases with S QL Ser ver Express: a Local or a Ser ver database. You should not use Push dependencies with a Local database. You should use Push dependencies only with a Server database. You cannot create new Ser ver databases w he n us in g Visual Web Developer. You can create a Server database by using the full version of Visual Studio 2010 or by down- loading Microsoft SQL Server Management Studio Express from the Microsoft MSDN website (msdn.microsoft.com). The advantage of using Push dependencies rather than Polling dependencies is that your ASP.NET application does not need to continuously poll your database for changes. When a change happens, your database is responsible for notifying your application of the change. However, there are significant limitations on the types of queries that you can use with Push dependencies. Following are some of the more significant limitations: . The query must use two-part table names (for example, dbo.Movies instead of Movies) to refer to tables. . The query must contain an explicit list of column names. (You cannot use *.) . The query cannot reference a view, derived table, temporary table, or table variable. . The query cannot reference large object types such as Text, NText, and Image columns. . The query cannot contain a subquery, outer join, or self join. . The query cannot use the DISTINCT, COMPUTE, COMPUTE BY, or INSERT keywords. . The query cannot use many aggregate functions including AVG, COUNT(*), MAX, and MIN. From the Library of Wow! eBook ptg 1409 Using SQL Cache Dependencies 29 This is not a complete list of query limitations. For the complete list, refer to the Creating a Query for Notification topic in the SQL Server 2005 Books Online or the MSDN website (msdn.microsoft.com). For example, the following simple query won’t work: SELECT * FROM Movies This query won’t work for two reasons. First, you cannot use the asterisk (*) to represent columns. Second, you must supply a two-part table name. The following query, on the other hand, works: SELECT Title, Director FROM dbo.Movies You can use Push SQL cache dependencies with stored procedures; however, each SELECT statement in the stored procedure must meet all the requirements just listed. Configuring Push SQL Cache Dependencies You must perform two configuration steps to enable Push SQL cache dependencies: 1. Configure your database by enabling the SQL Server Service Broker. 2. Configure your application by starting the notification listener. In this section, you learn how to perform both of these configuration steps. WARNING Unfortunately, when a Push SQL cache dependency fails, it fails silently, without adding an error message to the Event Log. This makes the situation especially difficult to debug. I recommend that after you make the configuration changes discussed in this section that you restart both your web server and database server. Configuring a Database for Push SQL Cache Dependencies Before you can use Push SQL cache dependencies, you must enable the Microsoft SQL Server Service Broker. You can check whether the Service Broker is activated for a particu- lar database by executing the following SQL query: SELECT name, is_broker_enabled FROM sys.databases If the Service Broker is not enabled for a database, you can enable it by executing an ALTER DATABASE command. For example, the following SQL command enables the Service Broker for a database named MyMovies: ALTER DATABASE MyMovies SET ENABLE_BROKER From the Library of Wow! eBook ptg 1410 CHAPTER 29 Caching Application Pages and Data Finally, the ASP.NET process must be supplied with adequate permissions to subscribe to query notifications. When an ASP.NET page is served from Internet Information Server, the page executes in the context of the NETWORK SERVICE account (for Microsoft Windows Server 2003) or the ASPNET account (for other operating systems such as Windows XP). Executing the following SQL command provides the local ASPNET account on a server named YOURSERVER with the required permissions: GRANT SUBSCRIBE QUERY NOTIFICATIONS TO “YOURSERVER\ASPNET” When you request an ASP.NET page when using the Visual Web Developer web server, an ASP.NET page executes in the security context of your current user account. Therefore, when using a file system website, you need to grant SUBSCRIBE QUERY NOTIFICATIONS permissions to your current account. NOTE Push SQL cache dependencies do not use the SQL Server Notification Services. Configuring an Application for Push SQL Cache Dependencies Before you can receive change notifications in your application, you must enable the query notification listener. You can enable the listener with the Global.asax file in Listing 29.45. LISTING 29.45 Global.asax <%@ Application Language=”C#” %> <%@ Import Namespace=”System.Data.SqlClient” %> <%@ Import Namespace=”System.Web.Configuration” %> <script runat=”server”> void Application_Start(object sender, EventArgs e) { // Enable Push SQL cache dependencies string conString = WebConfigurationManager.ConnectionStrings[“MyMovies”].ConnectionString; SqlDependency.Start(conString); } </script> The Application_Start handler executes once when your application first starts. In Listing 29.45, the SqlDependency.Start() method is called with a connection string to a SQL Express server database named MyMovies. From the Library of Wow! eBook ptg 1411 Using SQL Cache Dependencies 29 WARNING The code in Listing 29.45 is commented out in the Global.asax file in the code down- load from the website that accompanies this book so that it won’t interfere with all the previous code samples discussed in this chapter. You need to remove the comments to use the code samples in the following sections. Using Push SQL Cache Dependencies with Page Output Caching You can use Push SQL cache dependencies when caching an entire ASP.NET page. If the results of any SQL command contained in the page changes, the page is dropped automati- cally from the cache. The SqlCommand object includes a property named the NotificationAutoEnlist property. This property has the value True by default. When NotificationAutoEnlist is enabled, a Push cache dependency is created between the page and the command automatically. For example, the page in Listing 29.46 includes an <%@ OutputCache %> directive that includes a SqlDependency attribute. This attribute is set to the special value CommandNotification. LISTING 29.46 PushSQLOutputCache.aspx <%@ Page Language=”C#” %> <%@ OutputCache Duration=”9999” VaryByParam=”none” SqlDependency=”CommandNotification” %> <!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”> <html xmlns=”http://www.w3.org/1999/xhtml” > <head id=”Head1” runat=”server”> <title>Push SQL Output Cache</title> </head> <body> <form id=”form1” runat=”server”> <div> <%= DateTime.Now.ToString(“T”) %> <hr /> <asp:GridView id=”grdMovies” DataSourceID=”srcMovies” Runat=”server” /> <asp:SqlDataSource id=”srcMovies” ConnectionString=”<%$ ConnectionStrings:MyMovies %>” From the Library of Wow! eBook ptg 1412 CHAPTER 29 Caching Application Pages and Data SelectCommand=”SELECT Title, Director FROM dbo.Movies” Runat=”server” /> </div> </form> </body> </html> The page in Listing 29.46 includes a SqlDataSource control that retrieves all the records from the Movies database table. The SqlDataSource control uses a SQL query that explic- itly lists column names and uses a two-part table name. These are requirements when using Push dependencies. The page in Listing 29.46 displays the current time. If you request the page in your browser, and refresh the page, the time does not change. The time does not change until you modify the Movies database table. WARNING The page in Listing 29.46 connects to a Server database named MyMovies. You should not use Push dependencies with a Local SQL Express database. The page uses a data- base table named Movies, which was created with the following SQL command: CREATE TABLE Movies ( Id int IDENTITY NOT NULL, Title nvarchar(100) NOT NULL, Director nvarchar(50) NOT NULL, EntryDate datetime NOT NULL DEFAULT GetDate() ) WARNING You cannot use Push SQL cache dependencies with an <%@ OutputCache %> directive included in a User Control. In other words, you cannot use Push SQL cache dependen- cies with Partial Page Caching. Using Push SQL Cache Dependencies with DataSource Caching You also can use Push SQL cache dependencies with both the SqlDataSource and ObjectDataSource controls by setting the SqlCacheDependency property. When using Push rather than Polling dependencies, you need to set the SqlCacheDependency property to the value CommandNotification. From the Library of Wow! eBook ptg 1413 Using SQL Cache Dependencies 29 For example, the page in Listing 29.47 contains a SqlDataSource control that has both its EnableCaching and SqlDependency properties set. LISTING 29.47 PushSQLDataSourceCache.aspx <%@ Page Language=”C#” %> <!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”> <script runat=”server”> protected void srcMovies_Selecting(object sender, ➥SqlDataSourceSelectingEventArgs e) { lblMessage.Text = “Retrieving data from database”; } </script> <html xmlns=”http://www.w3.org/1999/xhtml” > <head id=”Head1” runat=”server”> <title>Push SQL DataSource Cache</title> </head> <body> <form id=”form1” runat=”server”> <div> <asp:Label id=”lblMessage” EnableViewState=”false” Runat=”server” /> <hr /> <asp:GridView id=”grdMovies” DataSourceID=”srcMovies” Runat=”server” /> <asp:SqlDataSource id=”srcMovies” ConnectionString=”<%$ ConnectionStrings:MyMovies %>” SelectCommand=”SELECT Title, Director FROM dbo.Movies” EnableCaching=”true” SqlCacheDependency=”CommandNotification” OnSelecting=”srcMovies_Selecting” Runat=”server” /> </div> </form> From the Library of Wow! eBook . Caching Application Pages and Data Finally, the ASP. NET process must be supplied with adequate permissions to subscribe to query notifications. When an ASP. NET page is served from Internet Information. command provides the local ASPNET account on a server named YOURSERVER with the required permissions: GRANT SUBSCRIBE QUERY NOTIFICATIONS TO “YOURSERVERASPNET” When you request an ASP. NET page. CommandNotification. LISTING 29 .46 PushSQLOutputCache.aspx <%@ Page Language=”C#” %> <%@ OutputCache Duration=”9999” VaryByParam=”none” SqlDependency=”CommandNotification” %> <!DOCTYPE html PUBLIC -/ /W3C//DTD