继上一篇文章DinnerNow中的WCF应用 --- 首页数据加载,我们大概了解了一些关于DinnerNow的基本项目结构,以及其中比较主要的两个解决方案文件。接下来我会继续以实际网上选餐流程来说明关于DinnerNow中的ASP.NET Ajax Extensions应用场景及其设计方案。

  首先请大家看一下这张图,它标明了在订餐这一业务流程中"查询餐馆"这一用例 DinnerNow所实际执行的方法顺序,因为下文中的一些主要的js方法调用也是以这张图中所标明的流程来顺序处理的.



  当然我们还要再次用VS2008打开上文中所说的两个解决方案文件:
    安装目录下\solution\DinnerNow - Web\DinnerNow - Web.sln
              \solution\DinnerNow - ServicePortfolio2\DinnerNow - ServicePortfolio2.sln

   不过这一回要说的重点内容集中在了DinnerNow - Web.sln下的DinnerNow.WebUX项目中.

  请看一下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
=   " " 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方法定义如下:

  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方法定义如:   

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脚本:

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代码如下:

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  =   "
""
                + menuItem.ImageLocation + 
" \ "  target='_blank'>  " MenuItemImage\ "  src=\ ""
                + menuItem.ImageLocation + 
" \ "  alt=\ ""
                + menuItem.Name +
" \ " /> " Img1\ "  src=\ ""
                + menuItem.ImageLocation+ 
" \ "  alt=\ ""
                + menuItem.Name+
" \ "  class=\ " hoverp_w_picpath_preview\ " />
Item #  "
                
+  i  +   "

"
                
+  menuItem.Name + "

"
                
+  menuItem.Description + "

Estimated Delivery Time: 
"
                
+  menuItem.PreparationTime + "  minutes
$ "
                
+  menuItem.Price + "


" noUnderline\ "  href=\ " javascript:AddItemToShoppingCart( ' "
                + menuItem.Description + "
' ' "
                + menuItem.ImageLocation + "
' ' "
                + menuItem.MenuId + "
' ' "
                + menuItem.MenuItemId + "
' ' "
                + menuItem.Name + "
' ' "
                + menuItem.PreparationTime + "
' ' "
                + menuItem.Price + "
' );\ " > " 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 " );
}