Sunday, June 25, 2006

Microsoft .NET Pet Shop 4(ZT)

Original Link: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnbda/html/petshop3x.asp
Executive Overview
The .NET Pet Shop application is designed to show the best practices for building enterprise, n-tier .NET 2.0 applications that may need to support a variety of database platforms and deployment scenarios.
The goals of the .NET Pet Shop 4 project are:
Productivity: Reduce the amount of code from .NET Pet Shop 3—we achieved nearly 25 percent reduction.
Migrate from ASP.NET 1.1 to 2.0: Leverage new features of ASP.NET 2.0—we took advantage of Master Pages, Membership, and Profile and designed a new, appealing user interface.

Figure 1. The .NET PetShop 4.0
Enterprise architecture: Build a flexible, best practice application—we implemented design patterns and separation of presentation, business, and data tiers.
Productivity
When compared to .NET Pet Shop 3, there is roughly 25 percent less code in .NET Pet Shop 4. The main gains in reducing lines of code are in the presentation layer and data access layer.
In the presentation layer, we reduced the code by roughly 25 percent. The sign-in and check-out steps are more compact than full ASP.NET pages and require less code and html. This is because the Wizard control natively handles the process flow code. Using the Master Page meant less html code and user controls to manage layout. Membership services handles authentication more succinctly than the Pet Shop 3 user management code.
We saw the biggest code savings in the data tier—36 percent. The account management code is replaced by the ASP.NET 2.0 SQL Membership Provider.
Table 1 gives a complete code count break down by tier.
Table 1. Code count comparison for .NET Pet Shop Version 3 versus Version 4

v3
v4
Presentation Layer
1,822
1,365
Model
349
395
Business Logic Layer
210
199
Data Access Layer
1,538
985
Total Lines of Code
3,919
2,944
This is further illustrated in the Figure 2.
Figure 2. Code Count Comparison Graph
.NET Pet Shop 4 introduces several new features, ranging from a custom ASP.NET 2.0 profile provider to asynchronous order processing with MSMQ. The code count for the new features is broken down in table 2:
Table 2. Code Count of New.NET Pet Shop 4 Features
Custom Profile
853
Oracle Membership
586
Cache Dependency
90
Message Queue
147
Total Lines of Code
1,676
Migration from ASP.NET 1.1 to 2.0
To accomplish the goals for .NET Pet Shop 4, we devised the following plan:
Use the Project Conversion Wizard to port the .NET Pet Shop 3.2 code base from ASP.NET 1.1 to ASP.NET 2.0.
Map out the ASP.NET 2.0 features that we want to include.
Implement an n-tier architecture that supports those features.
The Project Conversion Wizard
To start off, the Visual Studio.NET 2005 Project Conversion Wizard rapidly upgraded the .NET Pet Shop 3.2 code base. With this basic port we were able get a first glimpse at .NET Pet Shop 3.2 compiled and running on ASP.NET 2.0.
Changes Between Version 3 and Version 4
Based on moving the .NET Pet Shop 3.2 code base to run on the .NET Framework 2.0 and our research into ASP.NET 2.0, we came up with the following key features to implement in .NET Pet Shop 4.0:
System.Transactions instead of Serviced Components.
Generics for strongly typed collections instead of loosely typed ILists.
ASP.NET 2.0 Membership for user authentication and authorization.
Custom ASP.NET 2.0 Membership Provider for Oracle 10g.
ASP.NET 2.0 Custom Oracle and SQL Server Profile Providers for user state management.
Master Pages for consistent look and feel versus ASP.NET Web User Controls.
ASP.NET 2.0 Wizard control.
Database level cache invalidation using SqlCacheDependency instead of timeout based.
Enabling Asynchronous Order Processing built on message queuing.
What is System.Transactions?
System.Transactions is a new transaction control namespace in the .NET 2.0 Framework. It is a new way to handle distributed transactions without the overhead of COM+ registration and the COM+ catalog. Note that the Microsoft Distributed Transaction Coordinator is used to initiate the transactions.
See it in action
The Order.Insert() method in synchronous order processing uses System.Transactions to insert an order and update the inventory stock. We have implemented the Order.Insert() method by adding a reference to the System.Transaction namespace and wrapping the order insertion and inventory stock reduction methods inside of a TransactionScope, as shown in Code Listing 1.
Listing 1. System.Transactions in actionusing System;
using System.Transactions;
using PetShop.IBLLStrategy;
namespace PetShop.BLL {
///
/// This is a synchronous implementation of IOrderStrategy
/// By implementing IOrderStrategy interface, the developer can
/// add a new order insert strategy without re-compiling the whole
/// BLL.
///

public class OrderSynchronous : IOrderStrategy {
...
///
/// Inserts the order and updates the inventory stock within
/// a transaction.
///

/// All information about the order
public void Insert(PetShop.Model.OrderInfo order) {
using (TransactionScope ts = new
TransactionScope(TransactionScopeOption.Required)) {
dal.Insert(order);
// Update the inventory to reflect the current inventory
// after the order submission.
Inventory inventory = new Inventory();
inventory.TakeStock(order.LineItems);
// Calling Complete commits the transaction.
// Excluding this call by the end of TransactionScope's
// scope will rollback the transaction.
ts.Complete();
}
}
}
}
In .NET Pet Shop 3, distributed transactions are handled by Enterprise Services and require COM+ registration. The OrderInsert class is derived from a Serviced Component and transactions are handled by COM+. The service component is then registered using the regsvr32 command.
Listing 2. Pet Shop 3 Order Insertusing System;
using System.Collections;
using System.EnterpriseServices;
using System.Runtime.InteropServices;
...
namespace PetShop.BLL {
///
/// A business component to manage the creation of orders
/// Creation of an order requires a distributed transaction
/// so the Order class derives from ServicedComponents
///

[Transaction(System.EnterpriseServices.TransactionOption.Required)]
[ClassInterface(ClassInterfaceType.AutoDispatch)]
[ObjectPooling(MinPoolSize=4, MaxPoolSize=4)]
[Guid("14E3573D-78C8-4220-9649-BA490DB7B78D")]
public class OrderInsert : ServicedComponent {
...
///
/// A method to insert a new order into the system
/// The orderId will be generated within the method and should not
/// be supplied as part of the order creation the inventory will be
/// reduced by the quantity ordered.
///

/// All the information about the order
///
/// The new orderId is returned in the order object
///

[AutoComplete]
public int Insert(OrderInfo order) {
// Get an instance of the Order DAL using the DALFactory
IOrder dal = PetShop.DALFactory.Order.Create();
// Call the insert method in the DAL to insert the header
int orderId = dal.Insert(order);
// Get an instance of the Inventory business component
Inventory inventory = new Inventory();
inventory.TakeStock( order.LineItems);
...
// Set the orderId so that it can be returned to the caller
return orderId;
}
}
}
Benefit of System.Transactions
Moving from Enterprise Services to System.Transactions simplifies deployment as it does not require the use of the COM+ Catalog. In using the COM+ Catalog we were carrying around a lot of extra weight for just distributed transaction support. System.Transaction makes it really simple to program and deploy distributed applications in ASP.NET 2.0 applications. System.Transactions is also up to 50 percent more performant at runtime, due to removing the overhead of COM+ catalog lookups for object instantiation. As a final benefit, System.Transactions is able to detect, when running against SQL Server 2005, when a distributed transaction is running against two different databases that are hosted on a single instance of SQL Server 2005. In this case, it is able to promote the distributed transaction to a local transaction, which avoids all overhead associated with distributed transaction logging/two phase commits, and significantly increases performance.
Generics
What are Generics?
Whenever a collection of Pet Shop model objects is returned, we use a collection list of the generic type for that object. This is a new feature of C# 2.0 known as Generics.
See it in Action
We can see Generics in action from the GetProductsByCategory method shown in Code Listing 3.
Listing 3. Product.cs (Pet Shop 4.0) ///
/// A method to retrieve products by category name
///

/// The category name to search by
/// A Generic List of ProductInfo
public IList GetProductsByCategory(string category) {
// Return new if the string is empty
if (string.IsNullOrEmpty(category))
return new List();
// Run a search against the data store
return dal.GetProductsByCategory(category);
}
Here is the equivalent code in Pet Shop 3 that returns an IList:
Listing 4. Product.cs (Pet Shop 3) ///
/// A method to retrieve products by category name
///

/// The category name to search by
///
/// An interface to an arraylist of the search results
///

public IList GetProductsByCategory(string category) {
// Return null if the string is empty
if (category.Trim() == string.Empty)
return null;
// Get an instance of the Product DAL using the DALFactory
IProduct dal = PetShop.DALFactory.Product.Create();
// Run a search against the data store
return dal.GetProductsByCategory(category);
}
Benefits of Generics
Generics allow us to return strongly typed collections of objects as opposed to the IList collections in .NET Pet Shop 3. Generic strongly typed collections offer type safety, and perform better than regular collections. Additionally, Generic strongly typed collections will show up on Visual Studio 2005 Intellisense, which can increase developer productivity.
ASP.NET 2.0 Membership
Membership provides a common user authentication and management framework. .NET Pet Shop 4 uses the SQL Server Membership Provider when user information is stored in SQL Server and a custom Membership Provider when user information is stored in Oracle.
See it in Action
To implement Membership in .NET Pet Shop 4, the following steps are necessary:
Configure forms authentication.


To use the SQL Membership Provider, we had to install the membership database. The Membership database is created by ASP.NET when running the following command. %WinDir%\Microsoft.NET\Framework\<.NET version>\aspnet_regsql
-S -E -A all -d MSPetShop4Services
Configure the SQL Membership Provider.




The ASP.NET Login control encapsulates all of the login logic. The CreateUserWizard control handles new user registration.
Benefit of ASP.NET 2.0 Membership
With Membership services, we are able to use pre-built user authentication and registration controls instead of writing them from scratch. The end result is less code to write for login, login status, user identity, user registration, and password recovery.
Also, since Membership now resides on its own database, we are able to remove the Accounts table that is used in .NET Pet Shop 3 and use the Membership services database created by ASP.NET 2.0.
Custom Membership Provider for Oracle 10g
The .NET 2.0 Framework includes a SQL Server Membership provider. In order to maintain user accounts when the application uses an Oracle membership database, we created a custom membership provider implementation for Oracle. We only implemented the methods that are used by .NET Pet Shop 4, which are the CreateUser method and the Login method. This code, however, can be used and/or extended by any customer that wants to use Oracle10G with the ASP.NET membership services.
See it in Action
The CreateUser method is one of the implemented methods of the MembershipProvider class. It provides insight into how the OracleMembershipProvider works.
Listing 5. OracleMembershipProvider.cs CreateUser(...)using System;
using System.Configuration.Provider;
namespace PetShop.Membership {
class OracleMembershipProvider : MembershipProvider {


string password, string email, string passwordQuestion,
string passwordAnswer, bool isApproved, object userId,
out MembershipCreateStatus status) {

// create connection
OracleConnection connection =
new OracleConnection(OracleHelper.ConnectionStringMembership);
connection.Open();
OracleTransaction transaction =
connection.BeginTransaction(IsolationLevel.ReadCommitted);
try {
DateTime dt = DateTime.Now;
bool isUserNew = true;
// Step 1: Check if the user exists in the Users
// table: Create if not
int uid = GetUserID(transaction, applicationId, username, true,
false, dt, out isUserNew);
if (uid == 0) { // User not created successfully!
status = MembershipCreateStatus.ProviderError;
return null;
}
// Step 2: Check if the user exists in the Membership table: Error
// if yes
if (IsUserInMembership(transaction, uid)) {
status = MembershipCreateStatus.DuplicateUserName;
return null;
}
// Step 3: Check if Email is duplicate
if (IsEmailInMembership(transaction, email, applicationId)) {
status = MembershipCreateStatus.DuplicateEmail;
return null;
}
// Step 4: Create user in Membership table
int pFormat = (int)passwordFormat;
if (!InsertUser(transaction, uid, email, pass, pFormat, salt, "",
"", isApproved, dt)) {
status = MembershipCreateStatus.ProviderError;
return null;
}
// Step 5: Update activity date if user is not new
if(!isUserNew) {
if(!UpdateLastActivityDate(transaction, uid, dt)) {
status = MembershipCreateStatus.ProviderError;
return null;
}
}
status = MembershipCreateStatus.Success;
return new MembershipUser(this.Name, username, uid, email,
passwordQuestion, null, isApproved,
false, dt, dt, dt, dt, DateTime.MinValue);
}
catch(Exception) {
if(status == MembershipCreateStatus.Success)
status = MembershipCreateStatus.ProviderError;
throw;
}
finally {
if(status == MembershipCreateStatus.Success)
transaction.Commit();
else
transaction.Rollback();

connection.Close();
connection.Dispose();
}
}
The unimplemented methods are left as empty stubs like so:public override string GetUserNameByEmail(string email) {
throw new Exception("The method or operation is not implemented.");
}
Benefit of Membership Provider for Oracle 10g
We have implemented a custom Membership Provider since we want .NET Pet Shop 4 to store membership data in an Oracle database as well as in SQL Server. The provider model gives us the ability to integrate Oracle databases with ASP.NET 2.0 Membership Services simply and quickly.
ASP.NET 2.0 Profile
In ASP.NET 2.0, user information can be stored across multiple visits to a Web application in a new service called Profile. The Profile implementation for.NET Pet Shop 4 stores and retrieves users' shopping carts, wish lists, and account information. One key point here is that many customers will find that this can replace their use of the session object almost completely, providing a transacted, cluster-safe store for user session information. By default, the Profile service serializes the data as a BLOB that it stores into the database. However, higher performance can be achieved by implementing your own profile service serialization service. For PetShop 4, a custom implementation of the Profile service was created to reduce the serialization overhead.
See it in Action
Configure the Profile Providers.
Listing 6. Profile Provider Configuration











Migrate the Anonymous Profile.
Listing 7. Migrating Anonymous Profiles // Carry over profile property values from an anonymous to an
// authenticated state
void Profile_MigrateAnonymous(Object sender, ProfileMigrateEventArgs e) {
ProfileCommon anonProfile = Profile.GetProfile(e.AnonymousID);
// Merge anonymous shopping cart items to the authenticated
// shopping cart items
foreach (CartItemInfo cartItem in
anonProfile.ShoppingCart.CartItems)
Profile.ShoppingCart.Add(cartItem);
// Merge anonymous wishlist items to the authenticated wishlist
// items
foreach (CartItemInfo cartItem in anonProfile.WishList.CartItems)
Profile.WishList.Add(cartItem);
// Clean up anonymous profile
ProfileManager.DeleteProfile(e.AnonymousID);
AnonymousIdentificationModule.ClearAnonymousIdentifier();

// Save profile
Profile.Save();
}
Listing 8. Shopping Cart using System;
using System.Collections.Generic;
using PetShop.Model;
namespace PetShop.BLL {
///
/// An object to represent a customer's shopping cart.
/// This class is also used to keep track of customer's wish list.
///

[Serializable]
public class Cart {
// Internal storage for a cart
private Dictionary cartItems =
new Dictionary();
///
/// Calculate the total for all the cartItems in the Cart
///

public decimal Total {
get {
decimal total = 0;
foreach (CartItemInfo item in cartItems.Values)
total += item.Price * item.Quantity;
return total;
}
}
///
/// Update the quantity for item that exists in the cart
///

/// Item Id
/// Quantity
public void SetQuantity(string itemId, int qty) {
cartItems[itemId].Quantity = qty;
}
///
/// Return the number of unique items in cart
///

public int Count {
get { return cartItems.Count; }
}
///
/// Add an item to the cart.
/// When ItemId to be added has already existed, this method
/// will update the quantity instead.
///

/// Item Id of item to add
public void Add(string itemId) {
CartItemInfo cartItem;
if (!cartItems.TryGetValue(itemId, out cartItem)) {
Item item = new Item();
ItemInfo data = item.GetItem(itemId);
if (data != null) {
CartItemInfo newItem = new CartItemInfo(itemId,
data.ProductName, 1, (decimal)data.Price,
data.Name, data.CategoryId, data.ProductId);
cartItems.Add(itemId, newItem);
}
}
else
cartItem.Quantity++;
}
///
/// Add an item to the cart.
/// When ItemId to be added has already existed, this method
/// will update the quantity instead.
///

/// Item to add
public void Add(CartItemInfo item) {
CartItemInfo cartItem;
if (!cartItems.TryGetValue(item.ItemId, out cartItem))
cartItems.Add(item.ItemId, item);
else
cartItem.Quantity += item.Quantity;
}
///
/// Remove item from the cart based on itemId
///

/// ItemId of item to remove
public void Remove(string itemId) {
cartItems.Remove(itemId);
}
///
/// Returns all items in the cart. Useful for looping through
/// the cart.
///

/// Collection of CartItemInfo
public ICollection CartItems {
get { return cartItems.Values; }
}
///
/// Method to convert all cart items to order line items
///

/// A new array of order line items
public LineItemInfo[] GetOrderLineItems() {
LineItemInfo[] orderLineItems =
new LineItemInfo[cartItems.Count];
int lineNum = 0;
foreach (CartItemInfo item in cartItems.Values)
orderLineItems[lineNum] = new LineItemInfo(item.ItemId,
item.Name, ++lineNum, item.Quantity, item.Price);
return orderLineItems;
}
///
/// Clear the cart
///

public void Clear() {
cartItems.Clear();
}
}
}
Benefit of the ASP.NET 2.0 Profile
With ASP.NET 2.0, users' shopping carts are stored in a database and are persisted, so that if users come back 2-3 days later, they still have their cart. Additionally, the Profile service is "on demand," whereas session state objects get re-loaded per page on any page that references it; an advantage of Profile service is that it does not get loaded unless it's actually needed.
Furthermore, using the Profile feature we are able to remove Account and Profile tables from the existing Pet Shop 3 database—and this resulted in fewer lines of code in the Business Logic and Data Access Layers, as well.
Master Page
ASP.NET 2.0 provides a new technique for maintaining a consistent look and feel for an entire Web site by using a Master Page. The .NET Pet Shop 4 Master Page contains the header, LoginView control, navigation menu, and HTML for rendering content. All of the other Pet Shop Web forms are wired to use the Pet Shop 4 Master Page.
See it in Action
The .NET Pet Shop 4 Master Page is depicted in figure 3.
Figure 3. .NET Pet Shop 4 Master Page
Listing 9. Master Page wire-up
Benefit of ASP.NET 2.0 Master Pages
Using the Master Page, we are able to simply create a single layout that we can reuse for all of the .NET Pet Shop pages. Any changes to the layout during development are made directly to the Master Page, leaving the other pages simply for content. In contrast, the user interface in .NET Pet Shop 3 is implemented by encapsulating the header and navigation bar within an ASP.NET User Control called NavBar.ascx. Each of the Web forms in .NET Pet Shop 3 contain the NavBar user control as well as HTML to control the layout. Changing the layout would involve fumbling with the NavBar user control or modifying the HTML on each of the Web forms.
ASP.NET 2.0 Wizard Control
The check-out process in .NET Pet Shop 4 is contained within a single Wizard control that resides on the CheckOut page. The Wizard is a new control that provides a simple way to implement a step-by-step process. The Wizard control manages the navigation between forms, the data persistence, and the state management in each step.
See it in Action

Figure 4. Check-out Wizard control
Benefit of the ASP.NET 2.0 Wizard Control (Click on the image for a larger picture)
The process of checking out in .NET Pet Shop 3 involves a series of ASP.NET pages that communicate with each other. From the shopping cart, the user can go to the check-out page; from there, users enter their billing information and finally the order is processed. The flow is controlled by a custom class called CartController, which manages the communication between the steps using Session State.
Figure 5. .NET Pet Shop 3 Checkout Process
The Wizard Control makes implementing the checkout very simple in .NET Pet Shop 4 with less code.
Database Level Cache Invalidation
New to ASP.NET 2.0 is the SQL Cache Dependency object that can be used to invalidate the cache when the data from SQL Server has been changed. Pet Shop 4 uses the SQL Cache Dependency object for invalidating the Category, Products, and Item caches.
Out of the box, Pet Shop includes only the implementation for table-based cache dependency. Developers can implement their own caching invalidation mechanisms by extending the CacheDependency object. Once implemented, the CacheDependency for Pet Shop 4 can be configured from web.config.
Note that the SQL CacheDependency for Pet Shop 4 is only designed to run against SQL Server. For Oracle, .NET Pet Shop 4 will fall back to time-based cache expiration.
See it in Action
The cache dependency for SQL Server is shown in figure 6:
Figure 6. Pet Shop Table Cache Dependency
Benefit of Database Level Cache Invalidation
With cache invalidation we can keep presented content consistent with the data in the Pet Shop databases, yet still realize the benefits of object caching on the middle tier to reduce runtime processing requirements on the middle tier, and reduce database calls. This increases application scalability (it can handle more concurrent users), while also reducing load on the database.
Asynchronous Order Processing
One of the other changes that we have made is adding an option to configure whether the ordering process should commit the transactions directly (synchronously) to the databases or to a designated queue in which the orders will be processed at a later point (Asynchronous). In asynchronous order processing, when a user place an order, it goes to a queue. .NET Pet Shop 4 has an implementation for storing in Microsoft Messaging Queue (MSMQ). This queue of orders can be processed later by the Order Processor console app. An advantage of this approach is that the orders database does not even have to be running for customers to still be able to place orders. Since MSMQ is using a durable queue, all orders are still captured with no interruption for users, and will be inserted into the database once the processing application and the orders database come online again.
See it in Action
To handle the algorithm variations between synchronous and asynchronous order processing, we use the Strategy Pattern. In the Strategy Pattern, the order placement method is decoupled from the BLL.Order.Insert method. Based on the web.config setting for OrderStrategy, the corresponding Insert method is used instead. By default, the .NET Pet Shop is configured to work synchronously.
To configure the Order Strategy, change the OrderStrategyClass value from OrderSynchronous to OrderAsynchronous. In addition, for asynchronous order processing, MSMQ must be enabled with a private queue created for Pet Shop, as shown here.

Synchronous Order Placement
Figure 7 depicts synchronous order placement. When users check out their orders, the checkout button click event handler calls the Order Insert method within the BLL. For synchronous order placement, the BLL Order object uses the OrderSynchronous Insert method to insert a new order into the Orders database and then update the Inventory database to reflect the current inventory after the order has completed submission.
Figure 7. Synchronous order placement
Asynchronous Order Placement
Figure 8 depicts asynchronous order placement. On the Web site, when the user clicks the CheckOut button, the BLL Order Insert method is called. However, since the OrderStrategy is configured for Asynchronous, the OrderAsynchronous strategy is used. The OrderAsynchronous insert method plainly sends the order info to a queue.
Figure 8. Asynchronous Order Placement
Order Processor
The Order Processor is a console application that we created to receive the orders that are in the Messaging implementation and transcribe these orders into the Order and Inventory databases. The Order Processor works multi-threaded, and processes orders in batches. It re-uses the Synchronous order strategy to insert the new order into the Orders database and to decrement the Inventory database.
Benefit of Asynchronous Order Processing
Processing orders asynchronously can be found in many other enterprise applications. De-coupling the order process is one way we made .NET Pet Shop 4 perform better as the orders are processed in multi-threaded fashion.
Architecture
As with the previous versions of the .NET Pet Shop, the architecture focuses on a clean separation between user interface, application logic, and data. This clean separation allows us to change an implementation in one layer without affecting the other layers. For example, we can change the database vendor without having to change the business logic code.
The diagram in figure 9 depicts the high-level logical architecture for .NET Pet Shop 4. The Presentation Layer (WEB) contains the various user interface elements. The Business Logic Layer (BLL) holds the application logic and business components. The Data Access Layer (DAL) is responsible for interacting with the databases for data storage and retrieval. Each of the tiers will be discussed in more detail in the following sections.

Figure 9. Architecture diagram of .NET Pet Shop 4 (Click on the image for a larger picture)
Abstract Factory Pattern
.NET Pet Shop 4 uses the Abstract Factory Design Pattern, in which interfaces are used to create families of related or dependent objects without specifying their concrete classes. One example of this pattern is within the Data Access Layer tier, which has projects for IDAL, DAL Factory, Oracle DAL, and SQL Server DAL. Abstract factories are created for caching, inventory and orders data access, messaging, and profile data access.
Presentation Layer
ASP.NET 2.0 includes many built-in features that increase developer productivity. In building .NET Pet Shop 4, we have redesigned the user interface to take advantage of the new features that ASP.NET 2.0 provides, such as Master Pages, Themes, Skins, Wizard control, and Login control. To maintain the user accounts, we utilize the Membership provider instead of using ASP.NET Session state to store users' shopping carts and favorite products. The new Profile provider can store a strongly typed shopping cart that makes programming and managing user state much easier. Using all of these features, we are able to quickly implement the Pet Shop presentation layer changes.
User Interface Enhancements
.NET Pet Shop 4 sports a clean new look and feel. The new user interface supports a larger pets catalog and makes it easier for users to find and purchase the various new pets. When we changed the look and feel of the .NET Pet Shop user interface, we had fun with the sample pets available from the .NET Pet Shop. The .NET Pet Shop now houses penguins, bugs, pandas, and even skeletons, dinosaurs, and transparent cats! We also improve the shopping experience by adding a wish list, breadcrumb trail, and other subtleties.
Encrypting Configuration Information
The .NET Framework 2.0 introduces a protected configuration feature that we used to encrypt connection strings. With this feature we can encrypt the sensitive database username and password information.
The .NET Pet Shop Installer will automatically run a script to encrypt the connection strings stored within the web.config file when you select the "full source and database install" option.
To perform the configuration encryption on the "source only" install, run the EncryptWebConfig.bat file found in the installed directory.C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\aspnet_regiis.exe
-pef "connectionStrings"
"C:\Program Files\Microsoft\.NET Pet Shop 4.0\Web"
Business Logic Layer
The business logic for.NET Pet Shop 4 retains much of the business logic from the .NET Pet Shop 3, such as Model objects and how they are used. The few changes are the use of Generics, asynchronous order placement, and the System.Transactions namespace.
Model Objects
.NET Pet Shop 4 carries over Model objects from .NET Pet Shop 3. These objects are custom lightweight classes that mimic the structure of database tables. These objects are shared across the application layers as a way to communicate with each other. For example, when returning multiple products in a category, we are returning a collection of Product Model objects.
Data Access Layer
The BLL communicates with the Data Access Layer to access data from the Pet Shop 4 databases. .NET Pet Shop 4 uses four databases: Inventory, Orders, Membership, and Profile. As with .NET Pet Shop 3, this version supports both Oracle and SQL Server databases.
Order and Inventory Schema
The database schema for Orders and Inventory used in the .NET Pet Shop 4 is ported from the .NET Pet Shop 3. A few fields that are not used are removed. The databases have the following overall structure of tables:
Figure 10. Pet Shop Orders Database
Figure 11. Pet Shop Inventory Database
Profile Database Schema
The Profile database is used to store user specific information, such as account info and shopping cart contents. The database has the following overall structure of tables:
Figure 12. Pet Shop Profile Database
Conclusions
The Microsoft .NET Pet Shop 4.0 application serves to highlight the key technologies and architecture that can be used to build scalable enterprise Web applications. Due to the enhancements in ASP.NET 2.0, we are able to build an n-tier enterprise application more quickly, allowing us to spend time building a richer and more fully featured Pet Shop.
The key changes and new features of .NET 2.0 we targeted were:
System.Transactions: Allows faster processing of transactions and easier deployment without use of the COM+ catalog.
Generics: Allows us to return strongly typed collections of objects as opposed to the IList collections in .NET Pet Shop 3. Enables easier coding since Intellisense will recognize the typed objects in the collection.
ASP.NET 2.0 Membership Service: Provides a common user authentication and management framework that can dramatically reduce code associated with creating and maintaining user account information. Allowed us to use pre-built user authentication and registration controls instead of writing them from scratch. The end result is less code to write for login, login status, user identity, user registration, and password recovery.
ASP.NET 2.0 Profile Service: Replaces use of the session object for user-specific information such as the shopping cart. Provides a transacted, cluster-safe store for user session information that can be maintained across multiple user visits to the site.
ASP.NET 2.0 Master Page: Provides a new technique for maintaining a consistent look and feel for an entire Web site, and makes it easy to apply global changes to the look and feel of a site across many pages simply by updating the Master Page.
ASP.NET 2.0 Wizard Control: A new server-side control that provides a simple way to implement a step-by-step process. We used it to reduce the amount of coding in the checkout process for Pet Shop 4.0.
ASP.NET 2.0 is the SQL Cache Dependency: Allows middle-tier object caches to be invalidated automatically as backend database information changes. This will work with SQL 2000 at the table level (as we did with PetShop 4), and with SQL Server 2005 it can also work at the individual row level. With this feature, cached database information can always be kept up to date while still taking advantage of caching to reduce load on middle-tier and database servers.
Asynchronous Order Processing Option via Messaging: While not a .NET 2.0 feature (also available in .NET 1.1), we extended PetShop 4 with the ability to optionally use messaging via MSMQ and System.Messaging versus using standard synchronous transactions directly to the database. This decouples the order process for the orders database, providing an added degree of reliability and potentially scalability.

Friday, June 23, 2006

How to make call to USCIS(ZT)

Call 1-800-375-5283, then press the following: 1, 2, 6, 1, the case #, 3,and 4. I was transferred to VSC where I filed the 140 and 485.

Thursday, June 22, 2006

Ajax内部交流文档(ZT)

Ajax内部交流文档

一、使用Ajax的主要原因
  1、通过适当的Ajax应用达到更好的用户体验;
  2、把以前的一些服务器负担的工作转嫁到客户端,利于客户端闲置的处理能力来处理,减轻服务器和带宽的负担,从而达到节约ISP的空间及带宽租用成本的目的。

二、引用
Ajax这个概念的最早提出者Jesse James Garrett认为:
  Ajax是Asynchronous JavaScript and XML的缩写。
  Ajax并不是一门新的语言或技术,它实际上是几项技术按一定的方式组合在一在同共的协作中发挥各自的作用,它包括
  使用XHTML和CSS标准化呈现;
  使用DOM实现动态显示和交互;
  使用XML和XSLT进行数据交换与处理;
  使用XMLHttpRequest进行异步数据读取;
  最后用JavaScript绑定和处理所有数据;
  Ajax的工作原理相当于在用户和服务器之间加了—个中间层,使用户操作与服务器响应异步化。并不是所有的用户请求都提交给服务器,像—些数据验证和数据处理等都交给Ajax引擎自己来做,只有确定需要从服务器读取新数据时再由Ajax引擎代为向服务器提交请求。

图2-1

图2-2
三、概述
  虽然Garrent列出了7条Ajax的构成技术,但个人认为,所谓的Ajax其核心只有JavaScript、XMLHTTPRequest和DOM,如果所用数据格式为XML的话,还可以再加上XML这一项(Ajax从服务器端返回的数据可以是XML格式,也可以是文本等其他格式)。
  在旧的交互方式中,由用户触发一个HTTP请求到服务器,服务器对其进行处理后再返回一个新的HTHL页到客户端,每当服务器处理客户端提交的请求时,客户都只能空闲等待,并且哪怕只是一次很小的交互、只需从服务器端得到很简单的一个数据,都要返回一个完整的HTML页,而用户每次都要浪费时间和带宽去重新读取整个页面。
  而使用Ajax后用户从感觉上几乎所有的操作都会很快响应没有页面重载(白屏)的等待。
  1、XMLHTTPRequest
  Ajax的一个最大的特点是无需刷新页面便可向服务器传输或读写数据(又称无刷新更新页面),这一特点主要得益于XMLHTTP组件XMLHTTPRequest对象。这样就可以向再发桌面应用程序只同服务器进行数据层面的交换,而不用每次都刷新界面也不用每次将数据处理的工作提交给服务器来做,这样即减轻了服务器的负担又加快了响应速度、缩短了用户等候时间。
  最早应用XMLHTTP的是微软,IE(IE5以上)通过允许开发人员在Web页面内部使用XMLHTTP ActiveX组件扩展自身的功能,开发人员可以不用从当前的Web页面导航而直接传输数据到服务器上或者从服务器取数据。这个功能是很重要的,因为它帮助减少了无状态连接的痛苦,它还可以排除下载冗余HTML的需要,从而提高进程的速度。Mozilla(Mozilla1.0以上及NetScape7以上)做出的回应是创建它自己的继承XML代理类:XMLHttpRequest类。Konqueror (和Safari v1.2,同样也是基于KHTML的浏览器)也支持XMLHttpRequest对象,而Opera也将在其v7.6x+以后的版本中支持XMLHttpRequest对象。对于大多数情况,XMLHttpRequest对象和XMLHTTP组件很相似,方法和属性也类似,只是有一小部分属性不支持。
XMLHttpRequest的应用:

XMLHttpRequest对象在JS中的应用
var xmlhttp = new XMLHttpRequest();
微软的XMLHTTP组件在JS中的应用
var xmlhttp = new ActiveXObject(Microsoft.XMLHTTP);
var xmlhttp = new ActiveXObject(Msxml2.XMLHTTP);

XMLHttpRequest 对象方法

/**
* Cross-browser XMLHttpRequest instantiation.
*/

if (typeof XMLHttpRequest == "undefined") {
XMLHttpRequest = function () {
var msxmls = ["MSXML3", "MSXML2", "Microsoft"]
for (var i=0; i < msxmls.length; i++) {
try {
return new ActiveXObject(msxmls[i]+".XMLHTTP")
} catch (e) { }
}
throw new Error("No XML component installed!")
}
}
function createXMLHttpRequest() {
try {
// Attempt to create it "the Mozilla way"
if (window.XMLHttpRequest) {
return new XMLHttpRequest();
}
// Guess not - now the IE way
if (window.ActiveXObject) {
return new ActiveXObject(getXMLPrefix() + ".XmlHttp");
}
}
catch (ex) {}
return false;
};

XMLHttpRequest 对象方法 方法 描述
abort() 停止当前请求
getAllResponseHeaders() 作为字符串返问完整的headers
getResponseHeader("headerLabel") 作为字符串返问单个的header标签
open("method","URL"[,asyncFlag[,"userName"[, "password"]]]) 设置未决的请求的目标 URL, 方法, 和其他参数
send(content) 发送请求
setRequestHeader("label", "value") 设置header并和请求一起发送

XMLHttpRequest 对象属性 属性 描述
onreadystatechange 状态改变的事件触发器
readyState 对象状态(integer):
0 = 未初始化
1 = 读取中
2 = 已读取
3 = 交互中
4 = 完成
responseText 服务器进程返回数据的文本版本
responseXML 服务器进程返回数据的兼容DOM的XML文档对象
status 服务器返回的状态码, 如:404 = "文件末找到" 、200 ="成功"
statusText 服务器返回的状态文本信息

  2、JavaScript
  JavaScript是一在浏览器中大量使用的编程语言,,他以前一直被贬低为一门糟糕的语言(他确实在使用上比较枯燥),以在常被用来作一些用来炫耀的小玩意和恶作剧或是单调琐碎的表单验证。但事实是,他是一门真正的编程语言,有着自已的标准并在各种浏览器中被广泛支持。
  3、DOM
  Document Object Model。
  DOM是给 HTML 和 XML 文件使用的一组 API。它提供了文件的结构表述,让你可以改变其中的內容及可见物。其本质是建立网页与 Script 或程序语言沟通的桥梁。
  所有WEB开发人员可操作及建立文件的属性、方法及事件都以对象来展现(例如,document 就代表“文件本身“这个对像,table 对象则代表 HTML 的表格对象等等)。这些对象可以由当今大多数的浏览器以 Script 来取用。
  一个用HTML或XHTML构建的网页也可以看作是一组结构化的数据,这些数据被封在DOM(Document Object Model)中,DOM提供了网页中各个对象的读写的支持。
  4、XML
  可扩展的标记语言(Extensible Markup Language)具有一种开放的、可扩展的、可自描述的语言结构,它已经成为网上数据和文档传输的标准。它是用来描述数据结构的一种语言,就正如他的名字一样。他使对某些结构化数据的定义更加容易,并且可以通过他和其他应用程序交换数据。
  5、综合
  Jesse James Garrett提到的Ajax引擎,实际上是一个比较复杂的JavaScript应用程序,用来处理用户请求,读写服务器和更改DOM内容。
  JavaScript的Ajax引擎读取信息,并且互动地重写DOM,这使网页能无缝化重构,也就是在页面已经下载完毕后改变页面内容,这是我们一直在通过JavaScript和DOM在广泛使用的方法,但要使网页真正动态起来,不仅要内部的互动,还需要从外部获取数据,在以前,我们是让用户来输入数据并通过DOM来改变网页内容的,但现在,XMLHTTPRequest,可以让我们在不重载页面的情况下读写服务器上的数据,使用户的输入达到最少。
  基于XML的网络通讯也并不是新事物,实际上FLASH和JAVA Applet都有不错的表现,现在这种富交互在网页上也可用了,基于标准化的并被广泛支持和技术,并且不需要插件或下载小程序。
  Ajax是传统WEB应用程序的一个转变。以前是服务器每次生成HTML页面并返回给客户端(浏览器)。在大多数网站中,很多页面中至少90%都是一样的,比如:结构、格式、页头、页尾、广告等,所不同的只是一小部分的内容,但每次服务器都会生成所有的页面再返回给客户端,这无形之中是一种浪费,不管是对于用户的时间、带宽、CPU耗用,还是对于ISP的高价租用的带宽和空间来说。如果按一页来算,只能几K或是几十K可能并不起眼,但像SINA每天要生成几百万个页面的大ISP来说,可以说是损失巨大的。而AJAX可以所为客户端和服务器的中间层,来处理客户端的请求,并根据需要向服务器端发送请求,用什么就取什么、用多少就取多少,就不会有数据的冗余和浪费,减少了数据下载总量,而且更新页面时不用重载全部内容,只更新需要更新的那部分即可,相对于纯后台处理并重载的方式缩短了用户等待时间,也把对资源的浪费降到最低,基于标准化的并被广泛支持和技术,并且不需要插件或下载小程序,所以Ajax对于用户和ISP来说是双盈的。
  Ajax使WEB中的界面与应用分离(也可以说是数据与呈现分离),而在以前两者是没有清晰的界限的,数据与呈现分离的分离,有利于分工合作、减少非技术人员对页面的修改造成的WEB应用程序错误、提高效率、也更加适用于现在的发布系统。也可以把以前的一些服务器负担的工作转嫁到客户端,利于客户端闲置的处理能力来处理。

四、应用
  Ajax理念的出现,揭开了无刷新更新页面时代的序幕,并有代替传统web开发中采用form(表单)递交方式更新web页面的趋势,可以算是一个里程碑。但Ajax都不是适用于所有地方的,它的适用范围是由它的特性所决定的。
  举个应用的例子,是关于级联菜单方面的Ajax应用。
  我们以前的对级联菜单的处理是这样的:
  为了避免每次对菜单的操作引起的重载页面,不采用每次调用后台的方式,而是一次性将级联菜单的所有数据全部读取出来并写入数组,然后根据用户的操作用JavaScript来控制它的子集项目的呈现,这样虽然解决了操作响应速度、不重载页面以及避免向服务器频繁发送请求的问题,但是如果用户不对菜单进行操作或只对菜单中的一部分进行操作的话,那读取的数据中的一部分就会成为冗余数据而浪费用户的资源,特别是在菜单结构复杂、数据量大的情况下(比如菜单有很多级、每一级菜又有上百个项目),这种弊端就更为突出。
  如果在此案中应用Ajax后,结果就会有所改观:
  在初始化页面时我们只读出它的第一级的所有数据并显示,在用户操作一级菜单其中一项时,会通过Ajax向后台请求当前一级项目所属的二级子菜单的所有数据,如果再继续请求已经呈现的二级菜单中的一项时,再向后面请求所操作二级菜单项对应的所有三级菜单的所有数据,以此类推……这样,用什么就取什么、用多少就取多少,就不会有数据的冗余和浪费,减少了数据下载总量,而且更新页面时不用重载全部内容,只更新需要更新的那部分即可,相对于后台处理并重载的方式缩短了用户等待时间,也把对资源的浪费降到最低。
  此外,Ajax由于可以调用外部数据,也可以实现数据聚合的功能(当然要有相应授权),比如微软刚刚在3月15日发布的在线RSS阅读器BETA版;还可以利于一些开放的数据,开发自已的一些应用程序,比如用Amazon的数据作的一些新颖的图书搜索应用。
  总之,Ajax适用于交互较多,频繁读数据,数据分类良好的WEB应用。

五、Ajax的优势
  1、减轻服务器的负担。因为Ajax的根本理念是“按需取数据”,所以最大可能在减少了冗余请求和响影对服务器造成的负担;
  2、无刷新更新页面,减少用户实际和心理等待时间;
  首先,“按需取数据”的模式减少了数据的实际读取量,打个很形象的比方,如果说重载的方式是从一个终点回到原点再到另一个终点的话,那么Ajax就是以一个终点为基点到达另一个终点;

图5-1


图5-2
  其次,即使要读取比较大的数据,也不用像RELOAD一样出现白屏的情况,由于Ajax是用XMLHTTP发送请求得到服务端应答数据,在不重新载入整个页面的情况下用Javascript操作DOM最终更新页面的,所以在读取数据的过程中,用户所面对的也不是白屏,而是原来的页面状态(或者可以加一个LOADING的提示框让用户了解数据读取的状态),只有当接收到全部数据后才更新相应部分的内容,而这种更新也是瞬间的,用户几乎感觉不到。总之用户是很敏感的,他们能感觉到你对他们的体贴,虽然不太可能立竿见影的效果,但会在用户的心中一点一滴的积累他们对网站的依赖。
  3、更好的用户体验;
  4、也可以把以前的一些服务器负担的工作转嫁到客户端,利于客户端闲置的处理能力来处理,减轻服务器和带宽的负担,节约空间和带宽租用成本;
  5、Ajax由于可以调用外部数据;
  6、基于标准化的并被广泛支持和技术,并且不需要插件或下载小程序;
  7、Ajax使WEB中的界面与应用分离(也可以说是数据与呈现分离);
  8、对于用户和ISP来说是双盈的。

六、Ajax的问题
  1、一些手持设备(如手机、PDA等)现在还不能很好的支持Ajax;
  2、用JavaScript作的Ajax引擎,JavaScript的兼容性和DeBug都是让人头痛的事;
  3、Ajax的无刷新重载,由于页面的变化没有刷新重载那么明显,所以容易给用户带来困扰――用户不太清楚现在的数据是新的还是已经更新过的;现有的解决有:在相关位置提示、数据更新的区域设计得比较明显、数据更新后给用户提示等;
  4、对流媒体的支持没有FLASH、Java Applet好;

七、结束语
  更好的Ajax应用,需要更多的客户端的开发,和对当前的WEB应用理念的思考,而且良好的用户体验,来源于为处处用户考虑的理念,而不单纯是某种技术。