如何在ASPNETMVC中集成 AngularJSWord格式文档下载.docx
《如何在ASPNETMVC中集成 AngularJSWord格式文档下载.docx》由会员分享,可在线阅读,更多相关《如何在ASPNETMVC中集成 AngularJSWord格式文档下载.docx(13页珍藏版)》请在冰豆网上搜索。
"
~/Scripts/jquery-{version}.js"
));
~/bundles/bootstrap"
~/Scripts/bootstrap.js"
~/Scripts/respond.js"
));
bundles.Add(newStyleBundle("
~/Content/css"
~/Content/bootstrap.css"
~/Content/site.css"
~/Content/SortableGrid.css"
~/Content/angular-block-ui.min.css"
~/Content/font-awesome.min.css"
~/bundles/angular"
~/Scripts/angular.min.js"
~/Scripts/angular-route.min.js"
~/Scripts/angular-sanitize.min.js"
~/Scripts/angular-ui.min.js"
~/Scripts/angular-ui/ui-bootstrap.min.js"
~/Scripts/angular-ui/ui-bootstrap-tpls.min.js"
~/Scripts/angular-block-ui.js"
~/bundles/shared"
~/Views/Shared/CodeProjectBootstrap.js"
~/Views/Shared/AjaxService.js"
~/Views/Shared/AlertService.js"
~/Views/Shared/DataGridService.js"
~/Views/Shared/MasterController.js"
~/bundles/routing-debug"
~/Views/Shared/CodeProjectRouting-debug.js"
~/bundles/routing-production"
~/Views/Shared/CodeProjectRouting-production.js"
~/bundles/home"
~/Views/Home/IndexController.js"
~/Views/Home/AboutController.js"
~/Views/Home/ContactController.js"
~/Views/Home/InitializeDataController.js"
~/bundles/customers"
~/Views/Customers/CustomerMaintenanceController.js"
~/Views/Customers/CustomerInquiryController.js"
~/bundles/products"
~/Views/Products/ProductMaintenanceController.js"
~/Views/Products/ProductInquiryController.js"
}
}
缓存与ASP.NET捆绑
使用ASP.NET捆绑的优势是它的“cachebusting”的辅助方法,一旦你改变了CSS和JavaScript的缓存方式,这种方法将会使用自动引导的方式使捆绑的文件能够更容易的进行缓存。
下面的代码示例是在一个MVC的Razor视图中执行的(通常情况下,是在_Layout.cshtml母版页)。
所述的Scripts.Render方法将会在客户端渲染,并且当在非调试模式下执行时,它将会产生包的虚拟路径和结束包的序列号。
当你更改包的内容并重新发布你的应用程序时,包将会生成一个新的版本号,这有助于客户端上的浏览器缓存,并生成一个新的下载包。
//_Layout.cshtml
@Scripts.Render("
)
该Scripts.Render功能是一个很好的功能,但在此示例应用程序,我想使用在客户端一侧动态加载的客户和产品,所以我不能用渲染功能来渲染我的一些包,这是挑战的开始。
这个问题是以如何使用AngularJS从客户端JavaScript渲染服务器端的ASP.NET包开始的?
_Layout.cshtml-服务器端启动代码
一个使用ASP.NETMVC来引导AngularJS应用程序的好处是,你可以通过_Layout.cshtml主页中服务器端的代码,来加载和执行AngularJS的代码。
这是第一步,帮助解决我通过客户端代码渲染服务器端捆绑的窘境。
当然,你可以简单地嵌入脚本来标记客户端的代码,但我需要一种方法来渲染一个包和引用,并维护被追加到清除了缓存的包的目的自动版本号。
开始的时候,我在_Layout.cshtml母版页的顶部编写了一些服务器端代码。
我所做的头两件事情就是让从程序集信息类中获取应用的序列号,从应用程序设置中获取检索的基本URL。
这两个都将被之后HTML中的Razor视图引擎所解析。
下面的代码段,产生了我想根据需求动态加载的一些包,我不想当应用启动时加载所有的前期的包。
我需要的信息中的最重要一块是虚拟路径和每一次捆绑的长版本号。
幸运的是,访问捆绑信息的方法,本身就是一种捆绑的功能。
下面的代码行的关键行引用了BundleTable。
这行代码执行了ResolveBundleUrl,返回了该方法的虚拟路径以及每个引用的捆绑和版本号。
这些代码基本上生成一个包的列表并且将该列表转换成一个JSON集合。
后来这个JSON集被添加到AngularJS。
有一个JSON集合中的包的信息是,允许从客户端AngularJS应用程序加载服务器端捆绑的最初的方法。
@usingCodeProject.Portal.Models
@{
stringversion=typeof(CodeProject.Portal.MvcApplication).Assembly.GetName().Version.ToString();
stringbaseUrl=System.Configuration.ConfigurationManager.AppSettings["
BaseUrl"
].ToString();
List<
CustomBundle>
bundles=newList<
();
CodeProject.Portal.Models.CustomBundlecustomBundle;
string>
codeProjectBundles=newList<
codeProjectBundles.Add("
home"
);
customers"
products"
foreach(stringcontrollerincodeProjectBundles)
customBundle=newCodeProject.Portal.Models.CustomBundle();
customBundle.BundleName=controller;
customBundle.Path=BundleTable.Bundles.ResolveBundleUrl("
~/bundles/"
+controller);
customBundle.IsLoaded=false;
bundles.Add(customBundle);
BundleInformationbundleInformation=newBundleInformation();
bundleInformation.Bundles=bundles;
stringbundleInformationJSON=Newtonsoft.Json.JsonConvert.SerializeObject(
bundleInformation,Newtonsoft.Json.Formatting.None);
ASP.NET的捆绑类有很多的功能。
例如,如果你想通过捆绑所有文件进行迭代,你可以执行EnumerateFiles方法,返回一个特定的包内的每个文件的虚拟路径。
foreach(varfileinbundle.EnumerateFiles(newBundleContext(
newHttpContextWrapper(HttpContext.Current),BundleTable.Bundles,"
)))
stringfilePath=file.IncludedVirtualPath.ToString();
_Layout.cshtml-标题
在HTML文档的标题部分,有一个RequireJS的参考。
该应用程序通过客户端AngularJS代码使用了RequireJS动态的加载包。
RequireJS是一个加载了JavaScriptAPI模块的异步模块定义(AMD)。
RequireJS有许多功能,但是对于实例应用的目的,仅需要来自于RequireJS的请求功能以便在后面应用程序的使用。
此外,Scripts.Render和Styles.Render方法将在开始部分被执行。
当应用程序以调试模式执行或者EnableOptimizations被指为false时,渲染的方法将会在每一次捆绑中生成多个脚本。
当在发布模式和启用优化时,渲染方法将生成一个脚本标记来代表整个捆绑的版本戳。
这就导致了另外一个挑战,那就是应用需要支持发布模式下生成捆绑脚本标签的能力,和调试模式下生成独特文件的脚本标签的能力。
如果你想要在调试模式下为JavaScript代码设置断点,这点是很重要的。
因为如果在发布模式下,使用JavaScript代码的优化捆绑版本是不可能的。
最后,在标题部分,使用Razor语法的基本URL被早早地设定为服务器侧的基本URL变量。
<
!
--_Layout.cshtml-->
DOCTYPEhtml>
html>
head>
metacharset="
utf-8"
/>
metaname="
viewport"
content="
width=device-width,initial-scale=1.0"
>
metahttp-equiv="
Cache-Control"
no-cache,no-store,must-revalidate"
Pragma"
no-cache"
Expires"
0"
title>
AngularJSMVCCodeProject<
/titlev>
scriptsrc="
~/Scripts/require.js"
/script>
~/bundles/modernizr"
@Styles.Render("
basehref="
#baseUrl"
/head>
调试模式VS发布模式
当EnableOptimizations被设置为false,或者在调试模式运行时,该@Scripts.Render方法会在每一次捆绑中产生多种脚本标签。
如果你想设置断点并调试JavaScript文件,这是必要的。
你有另一种选择,就是在调试模式下,使用RenderFormat方法来选人客户脚本标签。
下面的代码片段包含在_layout.cshtml母版页中,当应用程序在调试模式下,RenderFormat会被使用。
在这种模式下,应用的版本序列号会被追加到捆绑中的所有JavaScript文件的脚本标签中。
对于标准的渲染脚本标签格式不包含追加版本号来说,这也算是个小弥补。
从VisualStudio中启动应用程序时,您可能会遇到浏览器缓存的问题。
同时也可能会花时间来猜测,你运行的是否是最新版本的JavaScript文件。
在浏览器中按F5可以解决这个问题。
为了避免这个问题一起发生,应用程序版本号会被附加到脚本标签中。
使用自动版本插件,版本号会在每次构建中自动递增。
使用这项技术,我能够知道每一次的编译和运行使用的是JavaScript文件的最新版本,这为我省了很多时间。
@if(HttpContext.Current.IsDebuggingEnabled)
@Scripts.RenderFormat("
scripttype=\"
text/javascript\"
src=\"
{0}?
ver="
+@version+"
\"
<
"
"
"
else
@Scripts.Render("
服务器端Razor数据和AngularJS之间的桥梁
现在,我已经创建了服务器端的捆绑数据的收集,接下来的挑战就是注入并创建服务器端和客户端AngularJS代码的桥梁。
在_Layout.cshtml母版页,我创建了能够创造一个AngularJS供应商的匿名的JavaScript功能。
最初我计划创建一个常规的AngularJS服务或者一个包含在_Layout.cshtml文件中能够使用Razor语法注入服务器端的方法集。
不幸的是,直到AngularJS配置阶段完成之后,才能提供AngularJS服务和方法集,因此我无法在主页中创建一个没有AngularJS错误的服务。
为了克服这个限制,则需要创建一个AngularJS的提供者。
提供者的功能是,能够创建提供方法集和服务的实例。
提供者允许你在Angular配置过程中创建和配置一个服务。
服务提供者名称是以他们所提供工作的提供商为开始的。
下面的代码片段中,代码创建一个“applicationConfiguration”提供商,这个提供商正在被applicationConfigurationProvider引用。
这个提供商将会在构造函数中被配置,来设定用于动态请求的应用所需的程序集版本号和捆绑列表。
MVCRazor代码在构造函数中会注入服务器端的数据。
(function(){
varcodeProjectApplication=angular.module('
codeProject'
codeProjectApplication.provider('
applicationConfiguration'
function(){
var_version;
var_bundles;
return{
setVersion:
function(version){
_version=version;
},
setBundles:
function(bundles){
_bundles=bundles;
getVersion:
function(){
return_version;
getBundles:
return_bundles;
$get:
version:
_version,
bundles:
_bundles
});
codeProjectApplication.config(function(applicationConfigurationProvider){
applicationConfigurationProvider.setVersion('
@version'
applicationConfigurationProvider.setBundles('
@Html.Raw(bundleInformationJSON)'
})();
路由产生和动态加载MVC捆绑
现在你可能已经看到了很多例子实现了每个内容页硬编码路径的AngularJS示例。
示例应用程序的路由使用基于约定的方法,这种方法允许路由表使用硬编码的路由方法来实现使用基于约定的方法。
所有的内容页和相关联的JavaScript文件将会遵循命名约定规则,这个规则允许该应用程序来解析路由并动态地确定每个内容页需要哪些JavaScript文件。
下面的示例应用程序的路由表只需要分析出三条路线:
一个用于根路径'
/'
一个标准路由路径,如'
/:
section/:
tree'
包含路由参数的路由,如'
tree/:
id'
我决定从ASP.NET捆绑中加载JavaScript文件,下面的路由配置代码需要包含一些applicationConfigurationProvider引用的代码,来用于创建保存之前的捆绑信息。
捆绑信息将会被解析为JSON集。
捆绑信息集将会用于返回虚拟的捆绑路径。
此外,JSON集将被用于跟踪被加载的捆绑。
一旦捆绑被加载,就不需要第二次捆绑了。
有几件事情需要写入路由代码中。
首先,每当用户选择一个页面来加载一定功能模块时,对于模块绑定的所有JavaScript文件需要被下载。
例如,当用户选择客户模式中的一个内容页面时,以下的代码会查看模块的捆绑是否已经通过JSON_bundlescollection的isLoaded属性被检查了,并且如果isLoaded为false,则捆绑将会被记载,isLoaded属性会被设置为true。
当确定需要下载哪些模式的捆绑时,有两件事情需要去加载捆绑:
deferredpromise和RequireJS。
deferredpromise可以帮助你异步运行函数,当它完成执行,就会返回。
现在,最后一块本文之谜是确定从客户端代码包中加载的方式。
我在以前的文章CodeP使用RequireJS(前面提到的)来动态加载JavaScript文件,我使用捆绑来加载RequireJS。
使用RequireJS“需求”的功能,我通过捆绑的虚拟路径进入需求功能。
事实证明,需求功能将会加载任何能够更好执行捆绑加载的路径。
当我第一次使用RequireJS的路径来下载捆绑时,我