繼上一篇文章DinnerNow中的WCF應用 --- 首頁數據加載,咱們大概瞭解了一些關於DinnerNow的基本項目結構,以及其中比較主要的兩個解決方案文件。接下來我會繼續以實際網上選餐流程來講明關於DinnerNow中的ASP.NET Ajax Extensions應用場景及其設計方案。javascript
首先請你們看一下這張圖,它標明瞭在訂餐這一業務流程中"查詢餐館"這一用例 DinnerNow所實際執行的方法順序,由於下文中的一些主要的js方法調用也是以這張圖中所標明的流程來順序處理的.
html
固然咱們還要再次用VS2008打開上文中所說的兩個解決方案文件:
安裝目錄下\solution\DinnerNow - Web\DinnerNow - Web.sln
\solution\DinnerNow - ServicePortfolio2\DinnerNow - ServicePortfolio2.slnjava
不過這一回要說的重點內容集中在了DinnerNow - Web.sln下的DinnerNow.WebUX項目中.ajax
請看一下search.aspx頁面的運行效果圖:
上圖中的數據請求在上一篇文章中已說過,就是:
service.FindRestaurant(PARAMETERS.map.PostalCode,
PARAMETERS.map.MenuType,
PARAMETERS.map.RestaurantCategory,
PARAMETERS.map.DeadLine,
onRestaurantSeachSuccess, //當操做請求成功後的回調方法
onRestaurantSeachFailed, null);
上面的回調方法的內容以下: 服務器
function onRestaurantSeachSuccess(searchResult)
//
searchResult爲請求返回的數據
{
var restaurantContainer
=
document.getElementById(
"
restaurantList
"
);
restaurantContainer.innerHTML
=
""
;
for
(var i
=
0
; i
<
searchResult.length; i
++
)
//
綁定數據並進行顯示
{
var restaurantHtml
=
"
<a href=\
"
javascript:restaurantSelection_Click(
'
"
+
searchResult[i].RestaurantId
+
"
', '
"
+
searchResult[i].LogoImageLocation
+
"
', '
"
+
searchResult[i].Name
+
"
');\
"
><
img src
=
\
""
+
searchResult[i].LogoImageLocation
+
"
\
"
alt
=
\
""
+
searchResult[i].Name
+
"
\
"
width
=
\
"
154\
"
height
=
\
"
90\
"
class
=
\
"
thingreenline\
"
/></
a
>
"
;
var restaurantElement
=
document.createElement(
"
span
"
);
restaurantElement.innerHTML
=
restaurantHtml;
restaurantContainer.appendChild(restaurantElement);
}
DisplayDiv(
"
SearchResultsDivision
"
);
}
經過這個方法的調用實現了上面圖中的顯示效果,當咱們單擊了其中某個餐館的圖標以後.
會顯示下面的頁面:
而單擊事件的執行方法以下:架構
function
restaurantSelection_Click(identifier, logo, name)
{
/*
********* RestaurantSelected **********
*/
生成餐館的信息,如LOGO,餐館名稱,說明等
document.getElementById(
"
restaurantImage
"
).src
=
logo;
document.getElementById(
"
restaurantName
"
).innerHTML
=
name;
document.getElementById(
"
restaurantDescription
"
).innerHTML
=
"
Since 1923, the offering fas, friendly and courteous service. We use only the best ingredients and maintain a skilled staff to answer your questions. We have built our reputation on our commitment to providing quality service, which has earned us many valuable customers.
"
;
document.getElementById(
"
restaurantMenuFeed
"
).href
=
"
service/syndication.svc/rss/restaurants/
"
+
name;
var
restaurant
=
document.getElementById(
"
restaurantID
"
);
restaurant.innerHTML
=
identifier;
/*
********* RestaurantSelected **********
*/
var
service
=
new
DinnerNow.Services.IMenuSearchService();
//
加載菜單列表
var
menuType
=
return_MenuType();
var
selectedMenuType
=
document.getElementById(
"
selectedMenuItemCategory
"
);
selectedMenuType.value
=
menuType;
service.GetMenuItemsForMenu(identifier,menuType,restaurantSelection_onSuccess,restaurantSelection_onFailed,
null
);
//
請求並加載菜單列表
service.GetMenuTypes(getMenuTypes_onSuccess, getMenuTypes_onFailed,
null
);
//
加載菜單類型(上圖中的屬性頁:Breakfast,Dinner,Lunch)
}
其中的GetMenuItemsForMenu,GetMenuTypes方法最終會去調用MenuSearchService類中的同名方法(MenuSearchService.cs文件在DinnerNow.ServicesDinnerNow - ServicePortfolio2.sln解決方案),因此這裏咱們還要再切換到ServicePortfolio2.sln下,找到位於DinnerNow.Services項目下的MenuSearchService.cs文件。其中的GetMenuItemsForMenu方法定義以下:app
public
IEnumerable
<
DinnerNow.Business.Data.RestaurantMenuItem
>
GetMenuItemsForMenu(
string
restaurantId,
string
menuType)
{
Business.Menu menu
=
new
DinnerNow.Business.Menu();
return
menu.GetMenuItemsForMenu(
new
Guid(restaurantId), menuType);
//
獲取指定類型的菜單數據
}
代碼段中的menu.GetMenuItemsForMenu方法定義如: ide
public
IEnumerable
<
DinnerNow.Business.Data.RestaurantMenuItem
>
GetMenuItemsForMenu(Guid restaurantId,
string
menuType)
{
var results
=
from mi
in
db.MenuItems
join m
in
db.Menus on mi.MenuId equals m.MenuId
where
m.RestaurantId
==
restaurantId
&&
m.MenuType
==
menuType
select
new
Business.Data.RestaurantMenuItem()
{
Description
=
mi.Description,
ImageLocation
=
mi.ImageLocation,
MenuId
=
mi.MenuId,
MenuItemId
=
mi.MenuItemId,
Name
=
mi.Name,
PreparationTime
=
mi.PreparationTime,
Price
=
mi.Price
};
return
results.ToList();
}
上面的LINQ查詢至關於下面的SQL腳本:ui
SELECT
[
t0
]
.
[
MenuItemId
]
,
[
t0
]
.
[
MenuId
]
,
[
t0
]
.
[
Name
]
,
[
t0
]
.
[
Description
]
,
[
t0
]
.
[
ImageLocation
]
,
[
t0
]
.
[
Price
]
,
[
t0
]
.
[
PreparationTime
]
FROM
[
dbo
]
.
[
MenuItem
]
AS
[
t0
]
INNER
JOIN
[
dbo
]
.
[
Menu
]
AS
[
t1
]
ON
[
t0
]
.
[
MenuId
]
=
[
t1
]
.
[
MenuId
]
WHERE
(
[
t1
]
.
[
RestaurantId
]
=
@p0
)
AND
(
[
t1
]
.
[
MenuType
]
=
@p1
)
而前面所說的GetMenuTypes方法你們也能夠找到它最終要去訪問的LINQ代碼以下:this
public
IEnumerable
<
DinnerNow.Business.Data.MenuType
>
GetMenuTypes()
{
var s
=
(from m
in
db.Menus
select
new
DinnerNow.Business.Data.MenuType()
{
MenuTypeName
=
m.MenuType.Trim()
}).Distinct();
return
s.ToList();
}
這裏由於代碼很簡單,就很少說了.
經過這個業務流程能夠看出DinnerNow基本架構思想:
ajax 請求數據 ---> wcf 服務配置 ---> linq 數據訪問.
這樣架構讓整個軟件的架構,流程及開發層次很是清楚。另外由於使用了 Ajax Extensions,使得開發和閱讀JS代碼感受就像是在寫C#代碼,使得軟件的可讀性和可維護性上也有很好提高和擴展空間.另外就是在UE上也使在咱們能夠在一個頁面上完成挑選餐館,選擇食物並進行訂餐的整個流程(接下來將會依次說明).避免了頻繁提交頁面請求而致使的操做繁鎖和服務器訪問超時問題,以及用戶等待時間過長(體驗差)和其它易於出錯的問題.
下面接着上面的JS代碼中的GetMenuItemsForMenu請求的回調方法restaurantSelection_onSuccess來繼續咱們的操做流程:
//
綁定菜單列表數據並進行顯示
function
restaurantSelection_onSuccess(result)
{
var
menuItemContainer
=
document.getElementById(
"
menuList
"
);
menuItemContainer.innerHTML
=
""
;
/*
******* MenuItems *********
*/
for
(
var
i
=
0
; i
<
result.length; i
++
)
{
var
menuItem
=
result[i];
var
menuItemHtml
=
"
<table width='100%' border='0' align='center' cellpadding='8' cellspacing='0' class='thinblueline'><tr><td width='150' align='center' valign='top'><div class='hoverarea'><div><a href=\
""
+ menuItem.ImageLocation +
"
\
"
target='_blank'> <img id=\
"
MenuItemImage\
"
src=\
""
+ menuItem.ImageLocation +
"
\
"
alt=\
""
+ menuItem.Name +
"
\
"
/><img id=\
"
Img1\
"
src=\
""
+ menuItem.ImageLocation+
"
\
"
alt=\
""
+ menuItem.Name+
"
\
"
class=\
"
hoverp_w_picpath_preview\
"
/></a></div></div></td><td valign='top'><strong>Item #
"
+
i
+
"
</strong><br/><strong>
"
+
menuItem.Name
+
"
</strong><br/>
"
+
menuItem.Description
+
"
<br/><br/><div align='left'><strong>Estimated Delivery Time:
"
+
menuItem.PreparationTime
+
"
minutes</strong></div></td><td width='80' align='right' valign='top'><strong>$
"
+
menuItem.Price
+
"
</strong><br/><br/><a class=\
"
noUnderline\
"
href=\
"
javascript:AddItemToShoppingCart(
'
"
+ menuItem.Description + "
'
,
'
"
+ menuItem.ImageLocation + "
'
,
'
"
+ menuItem.MenuId + "
'
,
'
"
+ menuItem.MenuItemId + "
'
,
'
"
+ menuItem.Name + "
'
,
'
"
+ menuItem.PreparationTime + "
'
,
'
"
+ menuItem.Price + "
'
);\
"
><img src=\
"
p_w_picpaths
/
selectbutton.gif\" border=\"0\"
/
><
/
a><
/
td
><
/
tr><
/
table
>
"
;
var menuItemElement=document.createElement(
"
span
"
);
menuItemElement.innerHTML = menuItemHtml;
menuItemContainer.appendChild(menuItemElement);
}
/******** MenuItems **********/
DisplayDivContent4(
"
shoppingCart
"
);
DisplayDiv(
"
MenuDivision
"
);
}
看到這裏,咱們在回到頁面上看一下當咱們單擊菜單旁邊的"select"按鈕以後所顯示的頁面內容:
而單擊所執行的JS方法以下(該方法用於將訂餐數據加載到購物車中):
function
AddItemToShoppingCart(description,p_w_picpathLocation,menuId,menuItemId,name,preparationTime,price)
{
var
menuItem
=
new
DinnerNow.Business.Data.RestaurantMenuItem();
menuItem.Description
=
description;
menuItem.ImageLocation
=
p_w_picpathLocation;
menuItem.MenuId
=
menuId;
menuItem.MenuItemId
=
menuItemId;
menuItem.Name
=
name;
menuItem.PreparationTime
=
preparationTime;
menuItem.Price
=
price;
var
restaurant
=
new
DinnerNow.Business.Data.RestaurantHeader();
restaurant.RestaurantId
=
document.getElementById(
"
restaurantID
"
).innerHTML;
restaurant.Name
=
document.getElementById(
"
restaurantName
"
).innerHTML;
restaurant.LogoImageLocation
=
document.getElementById(
"
restaurantImage
"
).src;
DinnerNow.ShoppingCartService.AddItem(menuItem,restaurant,menuSort,addItemToShoppingCart_onSuccess,addItemToShoppingCart_onFailed,
null
);
}
其中的DinnerNow.ShoppingCartService.AddItem調用會生成以下的ajax請求:
AddItem:
function
(selectedItem,restaurant,selectedSortOption,succeededCallback, failedCallback, userContext) {
//
/ <param name="selectedItem" type="DinnerNow.Business.Data.RestaurantMenuItem">DinnerNow.WebUX.MenuSearchService.RestaurantMenuItem</param>
//
/ <param name="restaurant" type="DinnerNow.Business.Data.RestaurantHeader">DinnerNow.WebUX.MenuSearchService.RestaurantHeader</param>
//
/ <param name="selectedSortOption" type="Number">System.Int32</param>
//
/ <param name="succeededCallback" type="Function" optional="true" mayBeNull="true"></param>
//
/ <param name="failedCallback" type="Function" optional="true" mayBeNull="true"></param>
//
/ <param name="userContext" optional="true" mayBeNull="true"></param>
return
this
._invoke(
this
._get_path(),
'
AddItem
'
,
false
,{selectedItem:selectedItem,restaurant:restaurant,selectedSortOption:selectedSortOption},succeededCallback,failedCallback,userContext); }
而最終ajax請求會成爲對以下方法的調用(DinnerNow.WebUX\Code\ShoppingCartService.cs文件中):
[OperationContract]
public
List
<
ShoppingCartItem
>
AddItem(RestaurantMenuItem selectedItem, RestaurantHeader restaurant,
int
selectedSortOption)
{
ShoppingCartItem shoppingCartItem
=
new
ShoppingCartItem()
{
DeliveryTime
=
selectedItem.PreparationTime,
MenuItemIdentifier
=
selectedItem.MenuItemId.ToString(),
MenuItemName
=
selectedItem.Name,
PreparationTime
=
selectedItem.PreparationTime,
Price
=
selectedItem.Price,
Quantity
=
1
,
RestaurantIdentifier
=
restaurant.RestaurantId.ToString(),
RestaurantImageLocation
=
restaurant.LogoImageLocation,
RestaurantName
=
restaurant.Name,
RestaurantItem
=
selectedItem,
Restaurant
=
restaurant
};
shoppingCart.AddItem(shoppingCartItem);
return
this
.RefreshItems(selectedSortOption);
}
經過這個方法咱們能夠實現將選定的食物放入購物車,並將購物車中已有商品的類型,價格,數據等信息返回到請求頁面中.並經過下面的JS方法來顯示相應的數據信息.
function
_refreshShoppingCart(result)
{
var
shoppingCartContainer
=
document.getElementById(
"
shoppingCartList
"
);
shoppingCartContainer.innerHTML
=
""
;
var
restaurantId
=
""
;
var
firsth
=
true
;
var
html
=
""
;
/*
******* Shopping Cart Items *********
*/
for
(
var
i
=
0
; i
<
result.length; i
++
)
{
var
shoppingCartItem
=
result[i];
var
subtotal
=
(shoppingCartItem.Price
*
shoppingCartItem.Quantity);
//
商品價格*數量
var
restaurantItemHtml
=
""
;
var
endPrevRestaurantItemHtml
=
""
;
if
(restaurantId
!=
shoppingCartItem.RestaurantIdentifier
&&
menuSort
!=
1
)
{
if
(
!
firsth)
endPrevRestaurantItemHtml
=
"
</table></td></tr>
"
;
firsth
=
false
;
restaurantId
=
shoppingCartItem.RestaurantIdentifier;
restaurantItemHtml
=
"
<table width='100%' border='0' align='center' cellpadding='4' cellspacing='4' bgcolor='#5686B4' class='thinblueline'><tr><td align='left' bgcolor='#31465B' class='boldWhite'>
"
+
shoppingCartItem.RestaurantName
+
"
</td></tr><tr><td>
"
;
}
var
shoppingCartHtml
=
"
<table width='100%' border='0' cellspacing='2' cellpadding='2' bgcolor='#5686B4'><tr><td align='left'><a class='noUnderline' href=\
"
javascript:DeleteItemFromShoppingCart(
'
"
+ shoppingCartItem.MenuItemIdentifier + "
'
);\
"
><img src='p_w_picpaths/delete.gif' alt='Remove item' width='17' height='16'/></a></td><td align='left' width='60%'>
"
+
shoppingCartItem.MenuItemName
+
"
</td><td align='left'><input type='text' id='
"
+
shoppingCartItem.MenuItemIdentifier
+
"
_itemViewQuantityBox' size='2' class='checkOutFormsField' onchange=\
"
updateShoppingCartQuantity(
'
"
+ shoppingCartItem.MenuItemIdentifier + "
'
);\
"
value ='
"
+
shoppingCartItem.Quantity
+
"
'></input></td><td align='left' nowrap='nowrap' class='bodyTextWhite'> $
"
+
subtotal
+
"
</td></tr>
"
;
html
+=
endPrevRestaurantItemHtml
+
restaurantItemHtml
+
shoppingCartHtml
+
"
</table><br/>
"
;
}
/*
******* Shopping Cart Items *********
*/
if
(html
!=
""
)
html
+=
"
</td></tr></table>
"
;
var
shoppingCartElement
=
document.createElement(
"
span
"
);
shoppingCartElement.innerHTML
=
html;
shoppingCartContainer.appendChild(shoppingCartElement);
//
ajax調用計算購物車中的Total,ETA信息
DinnerNow.ShoppingCartService.Totals(getTotals_onSuccess, getTotals_onFailed,
null
);
}
能夠看出,整個選購流程仍是有些複雜的,但在操做上卻很流暢,讓人感受不出什麼繁鎖.這其實都要得益於ajax的適當應用.固然微軟的Ajax Extensions無形中也下降了AJAX代碼的開發門檻:)
在下一篇文章中,咱們將會繼續訂餐流程,不太重點將會轉移動到DinnerNow - ServicePortfolio2.sln解決方案下,而且由於DinnerNow中使用了WWF(Windows Work Flow Foundation), 因此下一篇文章的內容可能會更偏向於WWF。若是你們感興趣的話,敬請留意:)
好了,今天的文章就先到這裏了,若是你們有什麼問題歡迎與我交流.
關鍵字:DinnerNow, Ajax Extensions