利用同一 ASP.NET 的多个代码框架
2013-06-20 14:00
274 查看
2012年,Microsoft推出了两个添加到ASP.NET工具包的新框架:WebAPI和SignalR。这两个框架为开发环境带来独特的开发方式,每个框架都有自身的独特之处:
WebAPI为开发人员提供了类似MVC的体验,以交付针对机器解释的内容。没有用户界面,并且事务以RESTful的方式出现。内容类型经过协商后,基于提交到WebAPI端点的HTTP标头,WebAPI就可以将内容自动格式化为JSON或XML。
SignalR是来自Microsoft的新型“实时Web”交付模型。此技术打开了客户端-服务器通信通道,支持进行从服务器到客户端的即时丰富通信。由于是通过服务器调用客户端来实现内容交互,SignalR中的内容交付模型颠覆了我们的正常预期。
Web窗体和MVC之间以及WebAPI和MVC之间的利弊权衡如图2所示。
图2每个ASP.NET组件框架的优点
工作效率与允许您快速开发和交付解决方案的功能相关。控制是可影响通过网络向连接用户传输的比特的程度。UI指示是否可以使用该框架来交付完整的UI。最后,“实时”表明框架能够在多大程度上及时显示即时更新的内容。
现在,在2013年,当我打开VisualStudio并试图启动一个ASP.NET项目时,我看到的是如图3和图4所示的对话框。
图3VisualStudio2012中的新建Web项目
图4VisualStudio2012中的新建项目模板对话框
在这些窗口中有一些棘手的问题。我应从什么类型的项目开始呢?我应使用什么模板才能最快获得解决方案呢?如果我想要添加每个模板的一些组件,将会怎样?我可以构建一个带有一些服务器控件和一个WebAPI的移动应用程序吗?
这是“同一ASP.NET”概念的核心:不要只选择这些框架中的一个,应使用最符合您的需求的部分构建解决方案。您有很多选择,不要局限于其中的一种。
我们来具体看看这是怎么实现的。为此,我将创建一个小型的Web应用程序,其中包含统一布局、一个搜索屏幕和一个产品列表的创建屏幕。搜索屏幕将由Web窗体和WebAPI支持,并显示来自SignalR的实时更新。创建屏幕将由MVC模板自动生成。通过使用第三方控件库和面向ASP.NETAJAX的TelerikRadControls,我还将确保Web窗体具有精美的外观。这些控件的试用版可从bit.ly/15o2Oab获得。
若要配置在这个项目中使用的Telerik控件,我需要在Web.config中进行一些更改,以添加通常会在标准TelerikRadControls项目中配置的HttpHandlers和HttpModules。首先,我将添加几行来定义TelerikAJAX控件UI皮肤:
<addkey="Telerik.Skin"value="WebBlue"/>[/code]
接下来,添加Telerik标签前缀:
<addtagPrefix="telerik"namespace="Telerik.Web.UI"assembly="Telerik.Web.UI"/>[/code]
我将为Telerik控件的Web.configHttpHandlers添加最少的内容:
<addpath="Telerik.Web.UI.WebResource.axd"type="Telerik.Web.UI.WebResource"[/code]
最后,我将添加到Telerik控件的Web.configHandlers:
<system.WebServer>[/code]
现在,我要为这个项目创建一个布局页,所以我将在“视图”|“共享”文件夹中创建一个Web窗体site.master页。对于此站点布局,我要将标准的徽标和菜单添加到所有页。我将通过简单地将图像拖到布局上来添加一个徽标图像。接下来,为了将一个主要的级联菜单添加到布局,我将从控件工具箱把RadMenu拖到图像正下方的设计器上。从设计器图面,通过右键单击菜单控件并选择“编辑项目”以得到图5所示的窗口,我可以快速构建菜单。
图5TelerikRadMenu配置窗口
我要重点关注的两个菜单项位于“产品”下:“搜索”和“新建”。对于每个项目,我已对NavigateUrl属性和文本进行如下设置:
<telerik:RadMenuItemText="Products">[/code]
菜单配置好以后,我现在遇到了新问题:我使用Web窗体定义布局,但需要承载MVC内容。这不是一个简单的问题,但它可以解决。
bit.ly/ehVY3H)。我将在这个项目中使用该技术。为了创建这样一个桥梁,我将配置一个引用母版页的简单Web窗体视图,称为RazorView.aspx:
为了让我的MVC控制器使用此视图,并使其基于Razor的视图得到执行,我需要对每个控制器进行扩展,以正确路由视图内容。这通过一个扩展方法来实现,该方法通过RazorView.aspx对模型、ViewData和TempData重新进行路由,如图6所示。
图6通过Web窗体母版页重新路由MVC视图的RazorView扩展方法
构建此方法后,我就可以通过母版页轻松路由所有MVC操作。下一个步骤是设置ProductsController以便能够创建产品。
图7BoardGame对象
接下来,我使用VisualStudio中标准的MVC工具创建一个空的ProductController。我将添加“视图”|“产品”文件夹,然后右键单击“产品”文件夹,再从“添加”菜单选择“视图”。此视图将支持新BoardGame的创建,所以我将使用图8中所示的选项创建。
图8创建“新建”视图
由于使用了MVC工具和模板,我不需要进行任何更改。创建的视图带有标签和验证,并可以使用我的母版页。图9显示如何在ProductController中定义“新建”操作。
图9通过RazorView的ProductController路由
MVC开发人员应熟悉此语法,唯一的变化是返回一个RazorView,而不是视图。_Products对象是一个此控制器中所定义的虚产品的静态只读集合,而不是使用此示例中的数据库:
添加这一行后,ASP.NET将把/Product/Search请求路由到位于/Product/Search.aspx的物理文件
接下来,我要配置一个显示目前产品及其库存水平的网格的搜索页面。我将在我的项目中创建一个“产品”文件夹并向其添加一个名为Search.aspx的新Web窗体。在此文件中,我将去掉除@Page指令之外的所有标记,并将MasterPageFile设置为前面定义的Site.Master文件。为了显示我的结果,我将选择TelerikRadGrid,这样我就可以快速配置并显示结果数据:
网格将自动生成绑定到其上的列,并提供排序和筛选功能。不过,我希望提高这一过程的动态性。我想在客户端实现数据的交付和管理。在此模型中,数据可以在Web窗体中无服务器端代码的情况下被发送并绑定。为此,我将添加一个负责交付并执行数据操作的WebAPI。
此代码经过少许格式化处理之后,返回静态列表中的BoardGame对象集合。通过使用[Queryable]修饰该方法并返回可查询的集合,WebAPI框架会自动接手处理OData筛选和排序命令。该方法还需要使用输入参数ODataQueryOptions进行配置,以便处理网格提交的筛选数据。
如果要在Search.aspx上配置网格以使用此新API,我需要向页面标记添加一些客户端设置。在此网格控件中,我使用ClientSettings元素和DataBinding设置定义客户端数据绑定。DataBinding设置列出了API的位置、响应格式类型和要查询的控制器名称,以及OData查询格式。通过这些设置和要在网格中显示的列的定义,我可以运行该项目,并看到绑定到_Products虚数据列表中数据的网格,如图10所示。
图10网格的完整格式源
Install-Package-preMicrosoft.AspNet.SignalR.SystemWeb[/code]
这些命令将在IISWeb服务器中安装要承载的ASP.NET服务器组件,并为Web窗体启动客户端JavaScript库。
SignalR服务器端组件被称为Hub,我将定义我自己的Hub,方法是在我的Web项目中的Hubs文件夹添加一个名为StockHub的类。StockHub需从Microsoft.AspNet.SignalR.Hub类继承而得。我定义了一个静态的System.Timers.Timer,使应用程序能够模拟库存水平的变化。模拟方式是每隔2秒(触发定时器Elapsed事件处理程序),我会随机设置一个随机选择产品的库存水平。一旦设置了产品库存水平,通过在客户端执行一个名为setNewStockLevel的方法,我将通知所有连接的客户端,如图11中所示。
图11SignalRHub服务器端组件
为使此Hub的数据可从服务器访问,我需要向RouteConfig添加一行,表明Hub的存在。通过在RouteConfig的RegisterRoutes方法中调用routes.MapHubs,我完成了SignalR服务器端的配置。
接下来,网格需要侦听这些来自服务器的事件。为此,我需要添加一些从NuGet安装的SignalR客户端库和MapHubs命令生成的代码的JavaScript引用。SignalR服务使用图12中显示的代码连接并公开客户端上的setNewStockLevel方法。
图12用于激活网格的SignalR客户端代码
在jQuery就绪事件处理程序中,我使用$.connection.stockHub语法建立了对StockHub的引用,名为stockWatcher。然后为stockWatcher的客户端属性定义了setNewStockLevel方法。此方法使用其他一些JavaScript帮助器方法遍历网格,找到相应产品的行,并使用jQueryUI提供的绚丽动画更改库存水平,如图13所示。
图13由WebAPI生成并由SignalR维护的网格搜索界面
WebAPI为开发人员提供了类似MVC的体验,以交付针对机器解释的内容。没有用户界面,并且事务以RESTful的方式出现。内容类型经过协商后,基于提交到WebAPI端点的HTTP标头,WebAPI就可以将内容自动格式化为JSON或XML。
SignalR是来自Microsoft的新型“实时Web”交付模型。此技术打开了客户端-服务器通信通道,支持进行从服务器到客户端的即时丰富通信。由于是通过服务器调用客户端来实现内容交互,SignalR中的内容交付模型颠覆了我们的正常预期。
Web窗体和MVC之间以及WebAPI和MVC之间的利弊权衡如图2所示。
图2每个ASP.NET组件框架的优点
框架 | 效率 | Control | UI | 实时 |
Web表单 | • | • | ||
MVC | • | • | ||
WebAPI | • | • | ||
SignalR | • |
现在,在2013年,当我打开VisualStudio并试图启动一个ASP.NET项目时,我看到的是如图3和图4所示的对话框。
图3VisualStudio2012中的新建Web项目
图4VisualStudio2012中的新建项目模板对话框
在这些窗口中有一些棘手的问题。我应从什么类型的项目开始呢?我应使用什么模板才能最快获得解决方案呢?如果我想要添加每个模板的一些组件,将会怎样?我可以构建一个带有一些服务器控件和一个WebAPI的移动应用程序吗?
我只能选择一种方法吗?
我只能选择一种方法吗?简短的答案是否定的,您并非只能选择其中一种框架来构建Web应用程序。现在已有一些技术允许您将Web窗体和MVC结合在一起使用。与显示的对话框窗口不同,WebAPI和SignalR可以作为功能轻松添加到Web应用程序中。请记住,所有ASP.NET内容都是通过一系列HttpHandlers和HttpModules呈现的。只要引用了正确的处理程序和模块,就可以使用任何一种框架构来建解决方案。这是“同一ASP.NET”概念的核心:不要只选择这些框架中的一个,应使用最符合您的需求的部分构建解决方案。您有很多选择,不要局限于其中的一种。
我们来具体看看这是怎么实现的。为此,我将创建一个小型的Web应用程序,其中包含统一布局、一个搜索屏幕和一个产品列表的创建屏幕。搜索屏幕将由Web窗体和WebAPI支持,并显示来自SignalR的实时更新。创建屏幕将由MVC模板自动生成。通过使用第三方控件库和面向ASP.NETAJAX的TelerikRadControls,我还将确保Web窗体具有精美的外观。这些控件的试用版可从
设置“示例项目”和“共享布局”
我只需要使用图3中所示的对话框创建一个项目就可以开始了。虽然我可以选择一个空的或Web窗体应用程序,可以选择的最完备解决方案则是MVC应用程序。以MVC项目开始是很好的选择,因为您从VisualStudio获得了所有的工具,可帮助您完成配置模型、视图和控制器的过程,并能够将Web窗体对象添加到项目文件结构中的任何位置。通过更改.csproj文件中的一些XML内容,可将MVC工具添加回现有Web应用程序。此过程可通过安装名为AddMvc3ToWebForms的NuGet包自动完成。若要配置在这个项目中使用的Telerik控件,我需要在Web.config中进行一些更改,以添加通常会在标准TelerikRadControls项目中配置的HttpHandlers和HttpModules。首先,我将添加几行来定义TelerikAJAX控件UI皮肤:
<addkey="Telerik.Skin"value="WebBlue"/>[/code]
</appSettings>[code]
接下来,添加Telerik标签前缀:
<addtagPrefix="telerik"namespace="Telerik.Web.UI"assembly="Telerik.Web.UI"/>[/code]
</controls>[code]
我将为Telerik控件的Web.configHttpHandlers添加最少的内容:
<addpath="Telerik.Web.UI.WebResource.axd"type="Telerik.Web.UI.WebResource"[/code]
verb="*"validate="false"/>
</httpHandlers>[code]
最后,我将添加到Telerik控件的Web.configHandlers:
<system.WebServer>[/code]
<validationvalidateIntegratedModeConfiguration="false"/>
<handlers>
<removename="Telerik_Web_UI_WebResource_axd"/>
<addname="Telerik_Web_UI_WebResource_axd"
path="Telerik.Web.UI.WebResource.axd"
type="Telerik.Web.UI.WebResource"verb="*"preCondition="integratedMode"/>[code]
现在,我要为这个项目创建一个布局页,所以我将在“视图”|“共享”文件夹中创建一个Web窗体site.master页。对于此站点布局,我要将标准的徽标和菜单添加到所有页。我将通过简单地将图像拖到布局上来添加一个徽标图像。接下来,为了将一个主要的级联菜单添加到布局,我将从控件工具箱把RadMenu拖到图像正下方的设计器上。从设计器图面,通过右键单击菜单控件并选择“编辑项目”以得到图5所示的窗口,我可以快速构建菜单。
图5TelerikRadMenu配置窗口
我要重点关注的两个菜单项位于“产品”下:“搜索”和“新建”。对于每个项目,我已对NavigateUrl属性和文本进行如下设置:
<telerik:RadMenuItemText="Products">[/code]
<Items>
<telerik:RadMenuItemText="Search"NavigateUrl="~/Product/Search"/>
<telerik:RadMenuItemText="New"NavigateUrl="~/Product/New"/>
</Items>
</telerik:RadMenuItem>[code]
菜单配置好以后,我现在遇到了新问题:我使用Web窗体定义布局,但需要承载MVC内容。这不是一个简单的问题,但它可以解决。
弥合鸿沟—将MVC配置为使用Web窗体母版页
像大多数人一样,我喜欢让事情变得简单。我来分享一下我为这个介于Web窗体和MVC之间的项目定义的布局。MattHawley设计了一项技术(有完善的文档),演示了如何结合使用Web窗体母版页和基于MVCRazor的视图(1.
2.<%@PageLanguage="C#"AutoEventWireup="true"
3.MasterPageFile="~/Views/Shared/Site.Master"
4.Inherits="System.Web.Mvc.ViewPage<dynamic>"%>
5.<%@ImportNamespace="System.Web.Mvc"%>
6.<asp:Contentid="bodyContent"runat="server"
7.ContentPlaceHolderID="body">
8.<%Html.RenderPartial((string)ViewBag._ViewName);%>
9.</asp:Content>
10.
为了让我的MVC控制器使用此视图,并使其基于Razor的视图得到执行,我需要对每个控制器进行扩展,以正确路由视图内容。这通过一个扩展方法来实现,该方法通过RazorView.aspx对模型、ViewData和TempData重新进行路由,如图6所示。
图6通过Web窗体母版页重新路由MVC视图的RazorView扩展方法
1.
2.publicstaticViewResultRazorView(thisControllercontroller,
3.stringviewName=null,objectmodel=null)
4.{
5.if(model!=null)
6.controller.ViewData.Model=model;
7.controller.ViewBag._ViewName=!string.IsNullOrEmpty(viewName)
8.?
9.viewName
10.:controller.RouteData.GetRequiredString("action");
11.returnnewViewResult
12.{
13.ViewName="RazorView",
14.ViewData=controller.ViewData,
15.TempData=controller.TempData
16.};
17.}
18.
构建此方法后,我就可以通过母版页轻松路由所有MVC操作。下一个步骤是设置ProductsController以便能够创建产品。
MVC和创建产品屏幕
此解决方案的MVC部分遵循相当标准的MVC方法。在我的项目的“模型”文件夹,我定义了一个简单的模型对象,称为BoardGame,如图7所示。图7BoardGame对象
1.
2.publicclassBoardGame
3.{
4.publicintId{get;set;}
5.publicstringName{get;set;}
6.[DisplayFormat(DataFormatString="$0.00")]
7.publicdecimalPrice{get;set;}
8.[Display(Name="Numberofitemsinstock"),Range(0,10000)]
9.publicintNumInStock{get;set;}
10.}
11.
接下来,我使用VisualStudio中标准的MVC工具创建一个空的ProductController。我将添加“视图”|“产品”文件夹,然后右键单击“产品”文件夹,再从“添加”菜单选择“视图”。此视图将支持新BoardGame的创建,所以我将使用图8中所示的选项创建。
图8创建“新建”视图
由于使用了MVC工具和模板,我不需要进行任何更改。创建的视图带有标签和验证,并可以使用我的母版页。图9显示如何在ProductController中定义“新建”操作。
图9通过RazorView的ProductController路由
1.
2.publicActionResultNew()
3.{
4.returnthis.RazorView();
5.}
6.[HttpPost]
7.publicActionResultNew(BoardGamenewGame)
8.{
9.if(!ModelState.IsValid)
10.{
11.returnthis.RazorView();
12.}
13.newGame.Id=_Products.Count+1;
14._Products.Add(newGame);
15.returnRedirect("~/Product/Search");
16.}
17.
MVC开发人员应熟悉此语法,唯一的变化是返回一个RazorView,而不是视图。_Products对象是一个此控制器中所定义的虚产品的静态只读集合,而不是使用此示例中的数据库:
1.
2.publicstaticreadonlyList<BoardGame>_Products=
3.newList<BoardGame>()
4.{
5.newBoardGame(){Id=1,Name="Chess",Price=9.99M},
6.newBoardGame(){Id=2,Name="Checkers",Price=7.99M},
7.newBoardGame(){Id=3,Name="Battleship",Price=8.99M},
8.newBoardGame(){Id=4,Name="Backgammon",Price=12.99M}
9.};
10.
配置基于Web窗体的搜索页
我希望用户访问产品搜索页面的URL有别于Web窗体的URL,能够便于用户搜索。随着ASP.NET2012.2的发布,现在可以轻松完成这一配置。只需打开App_Start/RouteConfig.cs文件,并调用EnableFriendlyUrls以启动此功能:1.
2.publicstaticvoidRegisterRoutes(
3.RouteCollectionroutes)
4.{
5.routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
6.routes.EnableFriendlyUrls();
7.routes.MapRoute(
8.name:"Default",
9.url:"{controller}/{action}/{id}",
10.defaults:new{controller="Home",action=
11."Index",id=UrlParameter.Optional}
12.);
13.}
14.
添加这一行后,ASP.NET将把/Product/Search请求路由到位于/Product/Search.aspx的物理文件
接下来,我要配置一个显示目前产品及其库存水平的网格的搜索页面。我将在我的项目中创建一个“产品”文件夹并向其添加一个名为Search.aspx的新Web窗体。在此文件中,我将去掉除@Page指令之外的所有标记,并将MasterPageFile设置为前面定义的Site.Master文件。为了显示我的结果,我将选择TelerikRadGrid,这样我就可以快速配置并显示结果数据:
1.
2.<%@PageLanguage="C#"AutoEventWireup="true"
3.CodeBehind="Search.aspx.cs"
4.Inherits="MvcApplication1.Product.Search"
5.MasterPageFile="~/Views/Shared/Site.Master"%>
6.<asp:Contentrunat="server"id="main"ContentPlaceHolderID="body">
7.<telerik:RadGridID="searchProducts"runat="server"width="500"
8.AllowFilteringByColumn="True"CellSpacing="0"GridLines="None"
9.AllowSorting="True">
10.
网格将自动生成绑定到其上的列,并提供排序和筛选功能。不过,我希望提高这一过程的动态性。我想在客户端实现数据的交付和管理。在此模型中,数据可以在Web窗体中无服务器端代码的情况下被发送并绑定。为此,我将添加一个负责交付并执行数据操作的WebAPI。
向组合中添加WebAPI
使用标准的“项目”|“新增”菜单,我将一个名为ProductController的WebAPI控制器添加到我的项目中名为“api”的文件夹。这有助于我清楚了解MVC控制器和API控制器之间的差别。此API将完成一项工作—以JSON格式交付网格数据并支持OData查询。要在WebAPI中完成这一点,我将编写一个Get方法并为其添加Queryable属性:1.
2.[Queryable]
3.publicIQueryable<dynamic>Get(ODataQueryOptionsoptions)
4.{
5.returnControllers.ProductController._Products.Select(b=>new
6.{
7.Id=b.Id,
8.Name=b.Name,
9.NumInStock=b.NumInStock,
10.Price=b.Price.ToString("$0.00")
11.}).AsQueryable();
12.}
13.
此代码经过少许格式化处理之后,返回静态列表中的BoardGame对象集合。通过使用[Queryable]修饰该方法并返回可查询的集合,WebAPI框架会自动接手处理OData筛选和排序命令。该方法还需要使用输入参数ODataQueryOptions进行配置,以便处理网格提交的筛选数据。
如果要在Search.aspx上配置网格以使用此新API,我需要向页面标记添加一些客户端设置。在此网格控件中,我使用ClientSettings元素和DataBinding设置定义客户端数据绑定。DataBinding设置列出了API的位置、响应格式类型和要查询的控制器名称,以及OData查询格式。通过这些设置和要在网格中显示的列的定义,我可以运行该项目,并看到绑定到_Products虚数据列表中数据的网格,如图10所示。
图10网格的完整格式源
1.
2.<telerik:RadGridID="searchProducts"runat="server"width="500"
3.AllowFilteringByColumn="True"CellSpacing="0"GridLines="None"
4.AllowSorting="True"AutoGenerateColumns="false"
5.>
6.<ClientSettingsAllowColumnsReorder="True"
7.ReorderColumnsOnClient="True"
8.ClientEvents-OnGridCreated="GridCreated">
9.<ScrollingAllowScroll="True"UseStaticHeaders="True"></Scrolling>
10.<DataBindingLocation="/api"ResponseType="JSON">
11.<DataServiceTableName="Product"Type="OData"/>
12.</DataBinding>
13.</ClientSettings>
14.<MasterTableViewClientDataKeyNames="Id"DataKeyNames="Id">
15.<Columns>
16.<telerik:GridBoundColumnDataField="Id"HeaderStyle-Width="0"
17.ItemStyle-Width="0"></telerik:GridBoundColumn>
18.<telerik:GridBoundColumnDataField="Name"HeaderText="Name"
19.HeaderStyle-Width="150"ItemStyle-Width="150">
20.</telerik:GridBoundColumn>
21.<telerik:GridBoundColumnItemStyle-CssClass="gridPrice"
22.DataField="Price"
23.HeaderText="Price"ItemStyle-HorizontalAlign="Right">
24.</telerik:GridBoundColumn>
25.<telerik:GridBoundColumnDataField="NumInStock"
26.ItemStyle-CssClass="numInStock"
27.HeaderText="#inStock"></telerik:GridBoundColumn>
28.</Columns>
29.</MasterTableView>
30.</telerik:RadGrid>
31.
使用实时数据激活网格
最后一个步骤是随着产品出货和进货实时显示库存水平变化的功能。我将添加一个SignalRhub以传输更新信息并在搜索网格上显示新值。要将SignalR添加到我的项目,我需要发出以下两个NuGet命令:Install-Package-preMicrosoft.AspNet.SignalR.SystemWeb[/code]
Install-Package-preMicrosoft.AspNet.SignalR.JS[code]
这些命令将在IISWeb服务器中安装要承载的ASP.NET服务器组件,并为Web窗体启动客户端JavaScript库。
SignalR服务器端组件被称为Hub,我将定义我自己的Hub,方法是在我的Web项目中的Hubs文件夹添加一个名为StockHub的类。StockHub需从Microsoft.AspNet.SignalR.Hub类继承而得。我定义了一个静态的System.Timers.Timer,使应用程序能够模拟库存水平的变化。模拟方式是每隔2秒(触发定时器Elapsed事件处理程序),我会随机设置一个随机选择产品的库存水平。一旦设置了产品库存水平,通过在客户端执行一个名为setNewStockLevel的方法,我将通知所有连接的客户端,如图11中所示。
图11SignalRHub服务器端组件
1.
2.publicclassStockHub:Hub
3.{
4.publicstaticreadonlyTimer_Timer=newTimer();
5.privatestaticreadonlyRandom_Rdm=newRandom();
6.staticStockHub()
7.{
8._Timer.Interval=2000;
9._Timer.Elapsed+=_Timer_Elapsed;
10._Timer.Start();
11.}
12.staticvoid_Timer_Elapsed(objectsender,ElapsedEventArgse)
13.{
14.varproducts=ProductController._Products;
15.varp=products.Skip(_Rdm.Next(0,products.Count())).First();
16.varnewStockLevel=p.NumInStock+
17._Rdm.Next(-1*p.NumInStock,100);
18.p.NumInStock=newStockLevel;
19.varhub=GlobalHost.ConnectionManager.GetHubContext<StockHub>();
20.hub.Clients.All.setNewStockLevel(p.Id,newStockLevel);
21.}
22.}
23.
为使此Hub的数据可从服务器访问,我需要向RouteConfig添加一行,表明Hub的存在。通过在RouteConfig的RegisterRoutes方法中调用routes.MapHubs,我完成了SignalR服务器端的配置。
接下来,网格需要侦听这些来自服务器的事件。为此,我需要添加一些从NuGet安装的SignalR客户端库和MapHubs命令生成的代码的JavaScript引用。SignalR服务使用图12中显示的代码连接并公开客户端上的setNewStockLevel方法。
图12用于激活网格的SignalR客户端代码
1.
2.<scriptsrc="/Scripts/jquery.signalR-1.0.0-rc2.min.js"></script>
3.<scriptsrc="/signalr/hubs"></script>
4.<scripttype="text/javascript">
5.vargrid;
6.$().ready(function(){
7.varstockWatcher=$.connection.stockHub;
8.stockWatcher.client.setNewStockLevel=function(id,newValue){
9.varrow=GetRow(id);
10.varorgColor=row.css("background-color");
11.row.find(".
12.numInStock").animate({
13.backgroundColor:"#FFEFD5"
14.},1000,"swing",function(){
15.row.find(".
16.numInStock").html(newValue).animate({
17.backgroundColor:orgColor
18.},1000)
19.});
20.};
21.$.connection.hub.start();
22.})
23.</script>
24.
在jQuery就绪事件处理程序中,我使用$.connection.stockHub语法建立了对StockHub的引用,名为stockWatcher。然后为stockWatcher的客户端属性定义了setNewStockLevel方法。此方法使用其他一些JavaScript帮助器方法遍历网格,找到相应产品的行,并使用jQueryUI提供的绚丽动画更改库存水平,如图13所示。
图13由WebAPI生成并由SignalR维护的网格搜索界面
总结
至此,我演示了如何构建一个ASP.NETMVC项目并添加Web窗体布局、第三方AJAX控件及相应的Web窗体。我使用MVC工具生成用户界面,并使用WebAPI和SignalR激活内容。此项目利用各组件的最佳功能,使用来自所有四个ASP.NET框架的功能,提供了一个一致的界面。您也来试试吧。对于您以后的项目,您将不必局限于一种ASP.NET框架。而是要各取所需。相关文章推荐
- 利用同一 ASP.NET 的多个代码框架
- 利用同一 ASP.NET 的多个代码框架
- 在Web应用程序开发过程中利用ASP.NET MVC框架的实战技巧
- Asp.Net异常:"由于代码已经过优化或者本机框架位于调用堆栈之上,无法计算表达式的值"的解决方法
- asp.net中利用正则表达式判断一个字符串是否为数字的代码
- asp.net利用存储过程分页代码收藏
- 利用ASP.NET框架创建网站登陆
- ASP.NET中一般处理程序报的错误:由于代码已经过优化或者本机框架位于调用堆栈之上,无法计算表达式的值
- LigerUI一个前台框架增、删、改asp.net代码的实现
- LigerUI一个前台框架增、删、改asp.net代码
- Asp.Net异常:"由于代码已经过优化或者本机框架位于调用堆栈之上,无法计算表达式的值"的解决方法
- 利用Flash Builder 4.5的数据服务功能,从Asp.net的WebService,自动生成调用代码
- asp.net利用存储过程分页代码
- 【转载】使用Json比用string返回数据更友好,也更面向对象一些 |Asp.net MVC 2.0 + Unity 2.0(IoC) + EF4.0 实例:RoRoWoBlog 开源项目框架代码
- 【.Net码农】Asp.Net异常:"由于代码已经过优化或者本机框架位于调用堆栈之上,无法计算表达式的值"的解决方法
- 利用Asp.net IO.File类完成文件新建复制删除操作(代码调试通过)(转)
- Asp.net利用JQuery AJAX实现无刷新评论思路与代码
- asp.net中利用ashx实现图片防盗链代码
- asp.net中利用Jquery+Ajax+Json实现无刷新分页的实例代码