1. Trang chủ
  2. » Công Nghệ Thông Tin

pro vb 2005 and the net 2.0 platform 2nd edition 2006 phần 10 docx

102 348 0

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 102
Dung lượng 1,13 MB

Nội dung

CHAPTER 27 ■ ASP.NET 2.0 STATE MANAGEMENT TECHNIQUES 933 ■Note If you wish to access the Cache from within Global.asax, you are required to use the Context property. However, if you are within the scope of a System.Web.UI.Page-derived type, you can make use of the Cache object directly. Now, understand that if you have no interest in automatically updating (or removing) an application-level data point (as seen here), the Cache object is of little benefit, as you can directly use the HttpApplicationState type. However, when you do wish to have a data point destroyed after a fixed point of time—and optionally be informed when this occurs—the Cache type is extremely helpful. The System.Web.Caching.Cache class defines only a small number of members beyond the type’s indexer. For example, the Add() method can be used to insert a new item into the cache that is not currently defined (if the specified item is already present, Add() does nothing). The Insert() method will also place a member into the cache. If, however, the item is currently defined, Insert() will replace the current item with the new type. Given that this is most often the behavior you will desire, I’ll focus on the Insert() method exclusively. Fun with Data Caching Let’s see an example. To begin, create a new ASP.NET web application named CacheState and insert a Global.asax file. Like an application-level variable maintained by the HttpApplicationState type, the Cache may hold any System.Object-derived type and is often populated within the Application_ Start() event handler. For this example, the goal is to automatically update the contents of a DataSet every 15 seconds. The DataSet in question will contain the current set of records from the Inventory table of the Cars database created during our discussion of ADO.NET. Given these stats, update your Global class type like so (code analysis to follow): <%@ Application Language="VB" %> <%@ Import Namespace = "System.Data.SqlClient" %> <%@ Import Namespace = "System.Data" %> <script runat="server"> ' Define a shared Cache member variable. Shared theCache As Cache Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs) ' First assign the shared 'theCache' variable. theCache = Context.Cache ' Add a DataSet to the cache via a helper function. AddDataSetToCache() End Sub Shared Sub AddDataSetToCache() ' When the application starts up, ' read the current records in the ' Inventory table of the Cars DB. Dim cn As SqlConnection = New SqlConnection _ ("data source=localhost;initial catalog=Cars; user id ='sa';pwd=''") Dim dAdapt As SqlDataAdapter = _ New SqlDataAdapter("Select * From Inventory", cn) Dim theCars As DataSet = New DataSet() dAdapt.Fill(theCars, "Inventory") 5785ch27.qxd 3/31/06 12:44 PM Page 933 CHAPTER 27 ■ ASP.NET 2.0 STATE MANAGEMENT TECHNIQUES934 ' Now store DataSet in the cache. theCache.Insert("AppDataSet", _ theCars, Nothing, _ DateTime.Now.AddSeconds(15), _ Cache.NoSlidingExpiration, _ CacheItemPriority.Default, _ New CacheItemRemovedCallback(AddressOf UpdateCarInventory)) End Sub ' The target for the CacheItemRemovedCallback delegate. Shared Sub UpdateCarInventory(ByVal key As String, ByVal item As Object, _ ByVal reason As CacheItemRemovedReason) Dim cn As SqlConnection = New SqlConnection _ ("data source=localhost;initial catalog=Cars; user id ='sa';pwd=''") Dim dAdapt As SqlDataAdapter = _ New SqlDataAdapter("Select * From Inventory", cn) Dim theCars As DataSet = New DataSet() dAdapt.Fill(theCars, "Inventory") ' Now store DataSet in the cache. theCache.Insert("AppDataSet", _ theCars, Nothing, _ DateTime.Now.AddSeconds(15), _ Cache.NoSlidingExpiration, _ CacheItemPriority.Default, _ New CacheItemRemovedCallback(AddressOf UpdateCarInventory)) End Sub </script> First, notice that the Global type has defined a shared Cache member variable. The reason is that you have defined two shared members (UpdateCarInventory() and AddDataSetToCache()) is that each method needs access the Cache (recall that shared members do not have access to inherited members, therefore you can’t use the Context property!). Inside the Application_Start() event handler, you fill a DataSet and place the object within the application cache. As you would guess, the Context.Cache.Insert() method has been overloaded a number of times. Here, you supply a value for each possible parameter. Consider the following commented call to Add(): ' Note! It is a syntax error to have comments after a line ' continuation character, but this is the cleanest way to show each param. theCache.Add("AppDataSet", _ ' Name used to identify item in the cache. theCars, _ ' Object to put in the cache. Nothing, _ ' Any dependencies for this object? DateTime.Now.AddSeconds(15), _ ' How long item will be in cache. Cache.NoSlidingExpiration, _ ' Fixed or sliding time? CacheItemPriority.Default, _ ' Priority level of cache item. ' Delegate for CacheItemRemove event New CacheItemRemovedCallback(UpdateCarInventory)) The first two parameters simply make up the name/value pair of the item. The third parameter allows you to define a CacheDependency type (which is Nothing in this case, as you do not have any other entities in the cache that are dependent on the DataSet). 5785ch27.qxd 3/31/06 12:44 PM Page 934 CHAPTER 27 ■ ASP.NET 2.0 STATE MANAGEMENT TECHNIQUES 935 ■Note The ability to define a CacheDependency type is quite interesting. For example, you could establish a dependency between a member and an external file. If the contents of the file were to change, the type can be automatically updated. Check out the .NET Framework 2.0 documentation for further details. The next three parameters are used to define the amount of time the item will be allowed to remain in the application cache and its level of priority. Here, you specify the read-only Cache. NoSlidingExpiration field, which informs the cache that the specified time limit (15 seconds) is absolute. Finally, and most important for this example, you create a new CacheItemRemovedCallback delegate type, and pass in the name of the method to call when the DataSet is purged. As you can see from the signature of the UpdateCarInventory() method, the CacheItemRemovedCallback delegate can only call methods that match the following signature: Sub UpdateCarInventory(ByVal key As String, ByVal item As Object, _ ByVal reason As CacheItemRemovedReason) End Sub So, at this point, when the application starts up, the DataSet is populated and cached. Every 15 seconds, the DataSet is purged, updated, and reinserted into the cache. To see the effects of doing this, you need to create a Page that allows for some degree of user interaction. Modifying the *.aspx File Update the UI of your initial *.aspx file as shown in Figure 27-6. Figure 27-6. The cache application GUI 5785ch27.qxd 3/31/06 12:44 PM Page 935 CHAPTER 27 ■ ASP.NET 2.0 STATE MANAGEMENT TECHNIQUES936 In the page’s Load event handler, configure your GridView to display the current contents of the cached DataSet the first time the user posts to the page (be sure to import the System.Data and System.Data.SqlClient namespaces within your *.vb code file): Protected Sub Page_Load(ByVal sender As Object, _ ByVal e As System.EventArgs) Handles Me.Load If Not IsPostBack Then carsGridView.DataSource = CType(Cache("AppDataSet"), DataSet) carsGridView.DataBind() End If End Sub In the Click event handler of the Add This Car button, insert the new record into the Cars database using an ADO.NET SqlCommand object. Once the record has been inserted, call a helper function named RefreshGrid(), which will update the UI via an ADO.NET SqlDataReader (so don’t forget to “use” the System.Data.SqlClient namespace). Here are the methods in question: Protected Sub btnAddCar_Click(ByVal sender As Object, ByVal e As EventArgs) ' Update the Inventory table ' and call RefreshGrid(). Dim cn As SqlConnection = New SqlConnection() cn.ConnectionString = "User ID=sa;Pwd=;Initial Catalog=Cars;Data Source=(local)" cn.Open() Dim sql As String Dim cmd As SqlCommand ' Insert new Car. sql = String.Format( _ "Insert Into Inventory(CarID, Make, Color, PetName) Values" & _ "('{0}', '{1}', '{2}', '{3}')", _ txtCarID.Text, txtCarMake.Text, txtCarColor.Text, txtCarPetName.Text) cmd = New SqlCommand(sql, cn) cmd.ExecuteNonQuery() cn.Close() RefreshGrid() End Sub Private Sub RefreshGrid() ' Populate grid. Dim cn As SqlConnection = New SqlConnection() cn.ConnectionString = "User ID=sa;Pwd=;Initial Catalog=Cars;Data Source=(local)" cn.Open() Dim cmd As SqlCommand = New SqlCommand("Select * from Inventory", cn) carsGridView.DataSource = cmd.ExecuteReader() carsGridView.DataBind() cn.Close() End Sub Now, to test the use of the cache, launch two instances of your web browser and navigate to this *.aspx page. At this point, you should see that both DataGrids display identical information. From one instance of the browser, add a new Car. Obviously, this results in an updated GridView viewable from the browser that initiated the postback. In the second browser instance, click the Refresh button. You should not see the new item, given that the Page_Load event handler is reading directly from the cache. (If you did see the value, the 15 seconds had already expired. Either type faster or increase the amount of time the DataSet will remain in the cache.) Wait a few seconds and click the Refresh button from the second browser instance one more time. Now you should see the new item, given that the DataSet in the cache has expired and the CacheItemRemovedCallback delegate target method has automatically updated the cached DataSet. 5785ch27.qxd 3/31/06 12:44 PM Page 936 CHAPTER 27 ■ ASP.NET 2.0 STATE MANAGEMENT TECHNIQUES 937 As you can see, the major benefit of the Cache type is that you can ensure that when a member is removed, you have a chance to respond. In this example, you certainly could avoid using the Cache and simply have the Page_Load() event handler always read directly from the Cars database. Never- theless, the point should be clear: the cache allows you to automatically refresh data using the cache mechanism. ■Note Unlike the HttpApplicationState type, the Cache class does not support Lock() and Unlock() methods. If you need to update interrelated items, you will need to directly make use of the types within the System.Threading namespace or the VB 2005 lock keyword. ■Source Code The CacheState files are included under the Chapter 27 subdirectory. Maintaining Session Data So much for our examination of application-level and cached data. Next, let’s check out the role of per-user data stores. As mentioned earlier, a session is little more than a given user’s interaction with a web application, which is represented via a unique HttpSessionState object. To maintain stateful information for a particular user, the HttpApplication-derived type and any System.Web.UI.Page- derived types may access the Session property. The classic example of the need to maintain per-user data would be an online shopping cart. Again, if ten people all log on to an online store, each indi- vidual will maintain a unique set of items that she (may) intend to purchase. When a new user logs on to your web application, the .NET runtime will automatically assign the user a unique session ID, which is used to identify the user in question. Each session ID is assigned a custom instance of the HttpSessionState type to hold on to user-specific data. Inserting or retrieving session data is syntactically identical to manipulating application data, for example: ' Add/retrieve a session variable for current user. Session("DesiredCarColor") = "Green" Dim color As String = CType(Session("DesiredCarColor"), String) The HttpApplication-derived type allows you to intercept the beginning and end of a session via the Session_Start() and Session_End() event handlers. Within Session_Start(), you can freely create any per-user data items, while Session_End() allows you to perform any work you may need to do when the user’s session has terminated: <%@ Application Language="VB" %> <script runat="server"> Sub Session_Start(ByVal sender As Object, ByVal e As EventArgs) ' Code that runs when a new session is started End Sub Sub Session_End(ByVal sender As Object, ByVal e As EventArgs) ' Code that runs when a session ends. ' Note: The Session_End event is raised ' only when the sessionstate mode ' is set to InProc in the Web.config file. ' If session mode is set to StateServer ' or SQLServer, the event is not raised. End Sub </script> 5785ch27.qxd 3/31/06 12:44 PM Page 937 CHAPTER 27 ■ ASP.NET 2.0 STATE MANAGEMENT TECHNIQUES938 ■Note The code comments that are placed within the Session_End() event handler will make much more sense when we examine the role of the ASP.NET session state server later in this chapter. Like the HttpApplicationState type, the HttpSessionState may hold any System.Object-derived type, including your custom classes. For example, assume you have a new web application (SessionState) that defines a class named UserShoppingCart: Public Class UserShoppingCart Public desiredCar As String Public desiredCarColor As String Public downPayment As Single Public isLeasing As Boolean Public dateOfPickUp As DateTime Public Overrides Function ToString() As String Return String.Format("Car: {0}<br>Color: {1}<br>" & _ "$ Down: {2}<br>Lease: {3} <br>Pick-up Date: {4}", _ desiredCar, desiredCarColor, downPayment, _ isLeasing, dateOfPickUp.ToShortDateString()) End Function End Class Within the Session_Start() event handler, you can now assign each user a new instance of the UserShoppingCart class: Sub Session_Start(ByVal sender As Object, ByVal e As EventArgs) Session("UserShoppingCartInfo") = New UserShoppingCart() End Sub As the user traverses your web pages, you are able to pluck out the UserShoppingCart instance and fill the fields with user-specific data. For example, assume you have a simple *.aspx page that defines a set of input widgets that correspond to each field of the UserShoppingCart type and a Button used to set the values and two Labels that will be used to display the user’s session ID and session information (see Figure 27-7). 5785ch27.qxd 3/31/06 12:44 PM Page 938 CHAPTER 27 ■ ASP.NET 2.0 STATE MANAGEMENT TECHNIQUES 939 Figure 27-7. The session application GUI The server-side Click event handler is straightforward (scrape out values from TextBoxes and display the shopping cart data on a Label type): Partial Class _Default Inherits System.Web.UI.Page Protected Sub btnSubmit_Click(ByVal sender As Object, _ ByVal e As System.EventArgs) Handles btnSubmit.Click ' Set current user prefs. Try Dim u As UserShoppingCart = _ CType(Session("UserShoppingCartInfo"), UserShoppingCart) u.dateOfPickUp = myCalendar.SelectedDate u.desiredCar = txtCarMake.Text u.desiredCarColor = txtCarColor.Text u.downPayment = Single.Parse(txtDownPayment.Text) u.isLeasing = chkIsLeasing.Checked lblUserInfo.Text = u.ToString() Session("UserShoppingCartInfo") = u Catch ex As Exception lblUserInfo.Text = ex.Message End Try End Sub End Class 5785ch27.qxd 3/31/06 12:44 PM Page 939 CHAPTER 27 ■ ASP.NET 2.0 STATE MANAGEMENT TECHNIQUES940 Within Session_End(), you may wish to persist the fields of the UserShoppingCart to a database or whatnot (however, as you will see at the conclusion of this chapter, the ASP.NET 2.0 profiles API will do so automatically). In any case, if you were to launch two or three instances of your browser of choice, you would find that each user is able to build a custom shopping cart that maps to his unique instance of HttpSessionState. Additional Members of HttpSessionState The HttpSessionState class defines a number of other members of interest beyond the type indexer. First, the SessionID property will return the current user’s unique ID. If you wish to view the automati- cally assigned session ID for this example, handle your Load event of your page as follows: Protected Sub Page_Load(ByVal sender As Object, _ ByVal e As System.EventArgs) Handles Me.Load If Not IsPostBack Then lblUserID.Text = String.Format("Here is your ID: {0}", _ Session.SessionID) End If End Sub The Remove() and RemoveAll() methods may be used to clear items out of the user’s instance of HttpSessionState: Session.Remove("SomeItemWeDontNeedAnymore") The HttpSessionState type also defines a set of members that control the expiration policy of the current session. Again, by default each user has 20 minutes of inactivity before the HttpSessionState object is destroyed. Thus, if a user enters your web application (and therefore obtains a unique session ID), but does not return to the site within 20 minutes, the runtime assumes the user is no longer interested and destroys all session data for that user. You are free to change this default 20-minute expiration value on a user-by-user basis using the Timeout property. The most common place to do so is within the scope of your Global.Session_Start() method: Sub Session_Start(ByVal sender As Object, ByVal e As EventArgs) ' Each user has 5 minutes of inactivity. Session.Timeout = 5 Session("UserShoppingCartInfo") _ = New UserShoppingCart() End Sub ■Note If you do not need to tweak each user’s Timeout value, you are able to alter the 20-minute default for all users via the Timeout attribute of the <sessionState> element within the web.config file (examined at the end of this chapter). The benefit of the Timeout property is that you have the ability to assign specific timeout values discretely for each user. For example, imagine you have created a web application that allows users to pay cash for a given membership level. You may say that Gold members should time out within one hour, while Wood members should get only 30 seconds. This possibility begs the question, how can you remember user-specific information (such as the current membership level) across web visits? One possible answer is through the user of the HttpCookie type. (And speaking of cookies . . .) ■Source Code The SessionState files are included under the Chapter 27 subdirectory. 5785ch27.qxd 3/31/06 12:44 PM Page 940 CHAPTER 27 ■ ASP.NET 2.0 STATE MANAGEMENT TECHNIQUES 941 Figure 27-8. Cookie data as persisted under Microsoft Internet Explorer Understanding Cookies The next state management technique examined here is the act of persisting data within a cookie, which is often realized as a text file (or set of files) on the user’s machine. When a user logs on to a given site, the browser checks to see whether the user’s machine has a cookie file for the URL in question and, if so, appends this data to the HTTP request. The receiving server-side web page could then read the cookie data to create a GUI that may be based on the current user preferences. I am sure you’ve noticed that when you visit one of your favorite websites, it somehow “just knows” the sort of content you wish to see. The reason (in part) may have to do with a cookie stored on your computer that contains information relevant to a given website. The exact location of your cookie files will depend on which browser you happen to be using. For those using Microsoft Internet Explorer, cookies are stored by default under C:\ Documents and Settings\ <loggedOnUser>\Cookies, as shown in Figure 27-8. The contents of a given cookie file will obviously vary among URLs, but keep in mind that they are ultimately text files. Thus, cookies are a horrible choice when you wish to maintain sensitive information about the current user (such as a credit card number, password, or whatnot). Even if you take the time to encrypt the data, a crafty hacker could decrypt the value and use it for purely evil pursuits. In any case, cookies do play a role in the development of web applications, so let’s check out how ASP.NET handles this particular state management technique. Creating Cookies First of all, understand that ASP.NET cookies can be configured to be either persistent or temporary. A persistent cookie is typically regarded as the classic definition of cookie data, in that the set of name/ value pairs is physically saved to the user’s hard drive. Temporary cookies (also termed session cookies) contain the same data as a persistent cookie, but the name/value pairs are never saved to the user’s machine; rather, they exist only within the HTTP header. Once the user logs off your site, all data contained within the session cookie is destroyed. ■Note Most browsers support cookies of up to 4,096 bytes. Because of this size limit, cookies are best used to store small amounts of data, such as a user ID that can be used to identify the user and pull details from a database. 5785ch27.qxd 3/31/06 12:44 PM Page 941 CHAPTER 27 ■ ASP.NET 2.0 STATE MANAGEMENT TECHNIQUES942 The System.Web.HttpCookie type is the class that represents the server side of the cookie data (persistent or temporary). When you wish to create a new cookie, you access the Response.Cookies property. Once the new HttpCookie is inserted into the internal collection, the name/value pairs flow back to the browser within the HTTP header. To check out cookie behavior firsthand, create a new ASP.NET web application (CookieStateApp) and create the UI displayed in Figure 27-9. Within the Button’s Click event handler, build a new HttpCookie and insert it into the Cookie collection exposed from the HttpRequest.Cookies property. Be very aware that the data will not persist itself to the user’s hard drive unless you explicitly set an expiration date using the HttpCookie.Expires property. Thus, the following implementation will create a temporary cookie that is destroyed when the user shuts down the browser: Protected Sub btnNewCookie_Click(ByVal sender As Object, _ ByVal e As System.EventArgs) Handles btnNewCookie.Click ' Make a new (temp) cookie. Dim theCookie As HttpCookie = _ New HttpCookie(txtCookieName.Text, _ txtCookieValue.Text) Response.Cookies.Add(theCookie) End Sub Figure 27-9. The UI of CookiesStateApp 5785ch27.qxd 3/31/06 12:44 PM Page 942 [...]... factors is to simplify the way in which information can be processed in a multiplatform, multi-architecture, and multilanguage universe To rectify the problem, theWSI initiative offers a nonproprietary web services specification to promote the interoperability of web services across platforms Under NET 2.0, the ConformsTo property of can be set to any value of the WsiProfiles enumeration:... check out where the profile API will be storing the specified data 5785ch27.qxd 3/31/06 12:44 PM Page 947 CHAPTER 27 ■ ASP .NET 2.0 STATE MANAGEMENT TECHNIQUES The ASPNETDB Database Recall that every ASP .NET 2.0 website built with Visual Studio 2005 automatically provides an App_Data subdirectory By default, the profile API (as well as other services, such as the ASP .NET role membership provider) is configured... HTTP-specific context used by the HTTP server to process web requests Server Provides access to the HttpServerUtility object for the current request Session Provides access to the HttpSessionState type for the current request SoapVersion Retrieves the version of the SOAP protocol used to make the SOAP request to the XML web service; new to NET 2.0 As you may be able to gather, if you wish to build a... in the ASP .NET Session State Server Under ASP .NET, you can instruct the runtime to host the session state *.dll in a surrogate process named the ASP .NET session state server (aspnet_state.exe) When you do so, you are able to offload the *.dll from aspnet_wp.exe into a unique *.exe, which can be located on any machine within the web farm Even if you intend to run the aspnet_state.exe process on the. .. (where the users are not part of a given domain), rest assured that the profile API integrates with the Forms-based authentication model of ASP NET and also supports the notion of “anonymous profiles,” which allow you to persist profile data for users who do not currently have an active identity on your site ■ Note This text does not cover the details of ASP .NET security, so consult the NET 2.0 Framework... using standard HTTP requests To be sure, of all the protocols in existence today, HTTP is the one specific wire protocol that all platforms can agree on (after all, HTTP is the backbone of the World Wide Web) 955 5785ch28.qxd 956 3/31/06 12:45 PM Page 956 CHAPTER 28 ■ UNDERSTANDING XML WEB SERVICES Another fundamental problem with proprietary remoting architectures is that they require the sender and receiver... types within the NET base class libraries) On the other hand, if you make use of the HTTP GET or HTTP POST protocols, you are restricted to a more limited set of core data XML schema types The NET XML Web Service Namespaces Now that you have a basic understanding of XML web services, we can get down to the business of building such a creature using the NET platform As you would imagine, the base class... same machine as the web server, you do gain the benefit of partitioning the state data in a unique process (as it is more durable) To make use of the session state server, the first step in doing so is to start the aspnet_state.exe Windows service on the target machine To do so at the command line, simply type net start aspnet_state Alternatively, you can start aspnet_state.exe using the Services applet... The Name Property The final property of the WebServiceAttribute type is Name, which is used to establish the name of the XML web service exposed to the outside world By default, the external name of a web service is identical to the name of the class type itself (Service by default) However, if you wish to decouple the NET class name from the underlying WSDL name, you can update the ... within our pages Accessing Profile Data Programmatically Recall that the whole purpose of the ASP .NET profile API is to automate the process of writing data to (and reading data from) a dedicated database To test this out for yourself, update the UI of your default.aspx file with a set of TextBoxes (and descriptive Labels) to gather the street address, city, and state of the user As well, add a Button . attribute. The default TCP/IP address value ( 127 .0. 0.1) points Figure 27 - 12. The Services applet 5785ch27.qxd 3/31 /06 12: 44 PM Page 945 CHAPTER 27 ■ ASP .NET 2. 0 STATE MANAGEMENT TECHNIQUES946 to the. ASP .NET 2. 0 website built with Visual Studio 20 05 automatically provides an App_Data subdirectory. By default, the profile API (as well as other services, such as the ASP .NET role membership provider). find that the cookie data has indeed been sent by your browser (see Figure 27 -11). Figure 27 - 10. The persistent cookie data 5785ch27.qxd 3/31 /06 12: 44 PM Page 943 CHAPTER 27 ■ ASP .NET 2. 0 STATE

Ngày đăng: 12/08/2014, 23:21