iOS培訓(xùn),Swift培訓(xùn),蘋果開發(fā)培訓(xùn),移動(dòng)開發(fā)培訓(xùn)

// BundleConfig.csusing System.Web;using System.Web.Optimization;public class BundleConfig
{    // For more information on bundling, visit http://go.microsft.com/fwlink/?LinkId=301862
    public static void RegisterBundles(BundleCollection bundles)
    {
        bundles.Add(new ScriptBundle("~/bundles/jquery").Include(            "~/Scripts/jquery-{version}.js"));

        bundles.Add(new ScriptBundle("~/bundles/bootstrap").Include(            "~/Scripts/bootstrap.js",            "~/Scripts/respond.js"
        ));

        bundles.Add(new StyleBundle("~/Content/css").Include(           "~/Content/bootstrap.css",           "~/Content/site.css",           "~/Content/SortableGrid.css",           "~/Content/angular-block-ui.min.css",           "~/Content/font-awesome.min.css"
        ));

        bundles.Add(new ScriptBundle("~/bundles/angular").Include(           "~/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-ui.min.js",           "~/Scripts/angular-block-ui.js"
        ));

        bundles.Add(new ScriptBundle("~/bundles/shared").Include(           "~/Views/Shared/CodeProjectBootstrap.js",           "~/Views/Shared/AjaxService.js",           "~/Views/Shared/AlertService.js",           "~/Views/Shared/DataGridService.js",           "~/Views/Shared/MasterController.js"
        ));

        bundles.Add(new ScriptBundle("~/bundles/routing-debug").Include(           "~/Views/Shared/CodeProjectRouting-debug.js"
        ));

        bundles.Add(new ScriptBundle("~/bundles/routing-production").Include(           "~/Views/Shared/CodeProjectRouting-production.js"
        ));

        bundles.Add(new ScriptBundle("~/bundles/home").Include(           "~/Views/Home/IndexController.js",           "~/Views/Home/AboutController.js",           "~/Views/Home/ContactController.js",           "~/Views/Home/InitializeDataController.js"
        ));

 
        bundles.Add(new ScriptBundle("~/bundles/customers").Include(           "~/Views/Customers/CustomerMaintenanceController.js",           "~/Views/Customers/CustomerInquiryController.js"
        ));

 
        bundles.Add(new ScriptBundle("~/bundles/products").Include(           "~/Views/Products/ProductMaintenanceController.js",           "~/Views/Products/ProductInquiryController.js"
        ));
    }
}

iOS培訓(xùn),Swift培訓(xùn),蘋果開發(fā)培訓(xùn),移動(dòng)開發(fā)培訓(xùn)

緩存與 ASP.NET 捆綁

使用 ASP.NET 捆綁的優(yōu)勢是它的“cache busting”的輔助方法,一旦你改變了 CSS 和 JavaScript 的緩存方式,這種方法將會使用自動(dòng)引導(dǎo)的方式使捆綁的文件能夠更容易的進(jìn)行緩存。下面的代碼示例是在一個(gè) MVC 的 Razor 視圖中執(zhí)行的(通常情況下,是在 _Layout.cshtml 母版頁)。所述的 Scripts.Render 方法將會在客戶端渲染,并且當(dāng)在非調(diào)試模式下執(zhí)行時(shí),它將會產(chǎn)生包的虛擬路徑和結(jié)束包的序列號。當(dāng)你更改包的內(nèi)容并重新發(fā)布你的應(yīng)用程序時(shí),包將會生成一個(gè)新的版本號,這有助于客戶端上的瀏覽器緩存,并生成一個(gè)新的下載包。

// _Layout.cshtml@Scripts.Render("~/bundles/customers")
@Scripts.Render("~/bundles/products")

該 Scripts.Render 功能是一個(gè)很好的功能,但在此示例應(yīng)用程序,我想使用在客戶端一側(cè)動(dòng)態(tài)加載的客戶和產(chǎn)品,所以我不能用渲染功能來渲染我的一些包,這是挑戰(zhàn)的開始。這個(gè)問題是以如何使用 AngularJS 從客戶端 JavaScript 渲染服務(wù)器端的 ASP.NET 包開始的?

_Layout.cshtml - 服務(wù)器端啟動(dòng)代碼

一個(gè)使用 ASP.NET MVC 來引導(dǎo) AngularJS 應(yīng)用程序的好處是,你可以通過 _Layout.cshtml 主頁中服務(wù)器端的代碼,來加載和執(zhí)行 AngularJS 的代碼。這是第一步,幫助解決我通過客戶端代碼渲染服務(wù)器端捆綁的窘境。當(dāng)然,你可以簡單地嵌入腳本來標(biāo)記客戶端的代碼,但我需要一種方法來渲染一個(gè)包和引用,并維護(hù)被追加到清除了緩存的包的目的自動(dòng)版本號。

開始的時(shí)候,我在 _Layout.cshtml 母版頁的頂部編寫了一些服務(wù)器端代碼。我所做的頭兩件事情就是讓從程序集信息類中獲取應(yīng)用的序列號,從應(yīng)用程序設(shè)置中獲取檢索的基本 URL。這兩個(gè)都將被之后 HTML 中的 Razor 視圖引擎所解析。

下面的代碼段,產(chǎn)生了我想根據(jù)需求動(dòng)態(tài)加載的一些包,我不想當(dāng)應(yīng)用啟動(dòng)時(shí)加載所有的前期的包。我需要的信息中的最重要一塊是虛擬路徑和每一次捆綁的長版本號。幸運(yùn)的是,訪問捆綁信息的方法,本身就是一種捆綁的功能。

下面的代碼行的關(guān)鍵行引用了 BundleTable。這行代碼執(zhí)行了 ResolveBundleUrl, 返回了該方法的虛擬路徑以及每個(gè)引用的捆綁和版本號。這些代碼基本上生成一個(gè)包的列表并且將該列表轉(zhuǎn)換成一個(gè) JSON 集合。后來這個(gè) JSON 集被添加到 AngularJS。有一個(gè) JSON 集合中的包的信息是,允許從客戶端 AngularJS 應(yīng)用程序加載服務(wù)器端捆綁的最初的方法。

iOS培訓(xùn),Swift培訓(xùn),蘋果開發(fā)培訓(xùn),移動(dòng)開發(fā)培訓(xùn)

// _Layout.cshtml@using CodeProject.Portal.Models
@{    string version = typeof(CodeProject.Portal.MvcApplication).Assembly.GetName().Version.ToString();    string baseUrl = System.Configuration.ConfigurationManager.AppSettings["BaseUrl"].ToString();

    List<CustomBundle> bundles = new List<CustomBundle>();
    CodeProject.Portal.Models.CustomBundle customBundle;

    List<string> codeProjectBundles = new List<string>();
    codeProjectBundles.Add("home");
    codeProjectBundles.Add("customers");
    codeProjectBundles.Add("products");    foreach (string controller in codeProjectBundles)
    {
        customBundle = new CodeProject.Portal.Models.CustomBundle();
        customBundle.BundleName = controller;
        customBundle.Path = BundleTable.Bundles.ResolveBundleUrl("~/bundles/" + controller);
        customBundle.IsLoaded = false;
        bundles.Add(customBundle);
    }

    BundleInformation bundleInformation = new BundleInformation();
    bundleInformation.Bundles = bundles;    string bundleInformationJSON = Newtonsoft.Json.JsonConvert.SerializeObject(
    bundleInformation, Newtonsoft.Json.Formatting.None);

}

iOS培訓(xùn),Swift培訓(xùn),蘋果開發(fā)培訓(xùn),移動(dòng)開發(fā)培訓(xùn)

ASP.NET 的捆綁類有很多的功能。例如,如果你想通過捆綁所有文件進(jìn)行迭代,你可以執(zhí)行 EnumerateFiles 方法,返回一個(gè)特定的包內(nèi)的每個(gè)文件的虛擬路徑。

foreach (var file in bundle.EnumerateFiles(new BundleContext(         new HttpContextWrapper(HttpContext.Current), BundleTable.Bundles, "~/bundles/shared")))
{    string filePath = file.IncludedVirtualPath.ToString();
}

_Layout.cshtml - 標(biāo)題

在 HTML 文檔的標(biāo)題部分,有一個(gè) RequireJS 的參考。該應(yīng)用程序通過客戶端 AngularJS 代碼使用了 RequireJS 動(dòng)態(tài)的加載包。RequireJS 是一個(gè)加載了 JavaScript API 模塊的異步模塊定義(AMD)。RequireJS 有許多功能,但是對于實(shí)例應(yīng)用的目的,僅需要來自于 RequireJS 的請求功能以便在后面應(yīng)用程序的使用。

此外,Scripts.Render 和 Styles.Render 方法將在開始部分被執(zhí)行。當(dāng)應(yīng)用程序以調(diào)試模式執(zhí)行或者 EnableOptimizations 被指為 false 時(shí),渲染的方法將會在每一次捆綁中生成多個(gè)腳本。當(dāng)在發(fā)布模式和啟用優(yōu)化時(shí),渲染方法將生成一個(gè)腳本標(biāo)記來代表整個(gè)捆綁的版本戳。

這就導(dǎo)致了另外一個(gè)挑戰(zhàn),那就是應(yīng)用需要支持發(fā)布模式下生成捆綁腳本標(biāo)簽的能力,和調(diào)試模式下生成獨(dú)特文件的腳本標(biāo)簽的能力。如果你想要在調(diào)試模式下為 JavaScript 代碼設(shè)置斷點(diǎn),這點(diǎn)是很重要的。因?yàn)槿绻诎l(fā)布模式下,使用 JavaScript 代碼的優(yōu)化捆綁版本是不可能的。

最后,在標(biāo)題部分,使用 Razor 語法的基本 URL 被早早地設(shè)定為服務(wù)器側(cè)的基本 URL 變量。

iOS培訓(xùn),Swift培訓(xùn),蘋果開發(fā)培訓(xùn),移動(dòng)開發(fā)培訓(xùn)

<!-- _Layout.cshtml -->

!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
<meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Expires" content="0" />

<title>AngularJS MVC Code Project</titlev>

<script src="~/Scripts/require.js"></script>@Scripts.Render("~/bundles/jquery")
@Scripts.Render("~/bundles/bootstrap")
@Scripts.Render("~/bundles/modernizr")
@Scripts.Render("~/bundles/angular")

@Styles.Render("~/Content/css")<base href="#baseUrl" />

</head>

iOS培訓(xùn),Swift培訓(xùn),蘋果開發(fā)培訓(xùn),移動(dòng)開發(fā)培訓(xùn)

調(diào)試模式VS發(fā)布模式

當(dāng) EnableOptimizations 被設(shè)置為 false,或者在調(diào)試模式運(yùn)行時(shí),該 @Scripts.Render 方法會在每一次捆綁中產(chǎn)生多種腳本標(biāo)簽。如果你想設(shè)置斷點(diǎn)并調(diào)試 JavaScript 文件,這是必要的。你有另一種選擇,就是在調(diào)試模式下,使用 RenderFormat 方法來選人客戶腳本標(biāo)簽。

下面的代碼片段包含在 _layout.cshtml 母版頁中,當(dāng)應(yīng)用程序在調(diào)試模式下,RenderFormat 會被使用。在這種模式下,應(yīng)用的版本序列號會被追加到捆綁中的所有JavaScript 文件的腳本標(biāo)簽中。對于標(biāo)準(zhǔn)的渲染腳本標(biāo)簽格式不包含追加版本號來說,這也算是個(gè)小彌補(bǔ)。

從 Visual Studio 中啟動(dòng)應(yīng)用程序時(shí),您可能會遇到瀏覽器緩存的問題。同時(shí)也可能會花時(shí)間來猜測,你運(yùn)行的是否是最新版本的 JavaScript 文件。在瀏覽器中按 F5 可以解決這個(gè)問題。為了避免這個(gè)問題一起發(fā)生,應(yīng)用程序版本號會被附加到腳本標(biāo)簽中。使用自動(dòng)版本插件,版本號會在每次構(gòu)建中自動(dòng)遞增。使用這項(xiàng)技術(shù),我能夠知道每一次的編譯和運(yùn)行使用的是 JavaScript 文件的最新版本,這為我省了很多時(shí)間。

iOS培訓(xùn),Swift培訓(xùn),蘋果開發(fā)培訓(xùn),移動(dòng)開發(fā)培訓(xùn)

// _Layout.cshtml@if (HttpContext.Current.IsDebuggingEnabled)
{
    @Scripts.RenderFormat("<script type=\"text/javascript\" src=\"{0}?ver =" + @version + " \">
                           </script>", "~/bundles/shared")
    @Scripts.RenderFormat("<script type=\"text/javascript\" src=\"{0}?ver =" + @version + " \">
                           </script>","~/bundles/routing-debug")}else{
    @Scripts.Render("~/bundles/shared")
    @Scripts.Render("~/bundles/routing-production")
}

iOS培訓(xùn),Swift培訓(xùn),蘋果開發(fā)培訓(xùn),移動(dòng)開發(fā)培訓(xùn)

服務(wù)器端 Razor 數(shù)據(jù)和 AngularJS 之間的橋梁

現(xiàn)在,我已經(jīng)創(chuàng)建了服務(wù)器端的捆綁數(shù)據(jù)的收集,接下來的挑戰(zhàn)就是注入并創(chuàng)建服務(wù)器端和客戶端 AngularJS 代碼的橋梁。在 _Layout.cshtml 母版頁,我創(chuàng)建了能夠創(chuàng)造一個(gè) AngularJS 供應(yīng)商的匿名的 JavaScript 功能。最初我計(jì)劃創(chuàng)建一個(gè)常規(guī)的 AngularJS 服務(wù)或者一個(gè)包含在 _Layout.cshtml 文件中能夠使用 Razor 語法注入服務(wù)器端的方法集。

不幸的是,直到 AngularJS 配置階段完成之后,才能提供 AngularJS 服務(wù)和方法集,因此我無法在主頁中創(chuàng)建一個(gè)沒有 AngularJS 錯(cuò)誤的服務(wù)。為了克服這個(gè)限制,則需要?jiǎng)?chuàng)建一個(gè) AngularJS 的提供者。提供者的功能是,能夠創(chuàng)建提供方法集和服務(wù)的實(shí)例。提供者允許你在 Angular 配置過程中創(chuàng)建和配置一個(gè)服務(wù)。

服務(wù)提供者名稱是以他們所提供工作的提供商為開始的。下面的代碼片段中,代碼創(chuàng)建一個(gè)“applicationConfiguration”提供商,這個(gè)提供商正在被 applicationConfigurationProvider 引用。這個(gè)提供商將會在構(gòu)造函數(shù)中被配置,來設(shè)定用于動(dòng)態(tài)請求的應(yīng)用所需的程序集版本號和捆綁列表。MVC Razor 代碼在構(gòu)造函數(shù)中會注入服務(wù)器端的數(shù)據(jù)。

iOS培訓(xùn),Swift培訓(xùn),蘋果開發(fā)培訓(xùn),移動(dòng)開發(fā)培訓(xùn)

// _Layout.cshtml(function () {        var codeProjectApplication = 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: function () {                return _bundles;
            },

            $get: function () {                return {
                    version: _version,
                    bundles: _bundles
                }
            }
       }
    });

    codeProjectApplication.config(function (applicationConfigurationProvider) {
        applicationConfigurationProvider.setVersion('@version');
        applicationConfigurationProvider.setBundles('@Html.Raw(bundleInformationJSON)');
    });
})();

iOS培訓(xùn),Swift培訓(xùn),蘋果開發(fā)培訓(xùn),移動(dòng)開發(fā)培訓(xùn)

路由產(chǎn)生和動(dòng)態(tài)加載 MVC 捆綁

現(xiàn)在你可能已經(jīng)看到了很多例子實(shí)現(xiàn)了每個(gè)內(nèi)容頁硬編碼路徑的 AngularJS 示例。示例應(yīng)用程序的路由使用基于約定的方法,這種方法允許路由表使用硬編碼的路由方法來實(shí)現(xiàn)使用基于約定的方法。所有的內(nèi)容頁和相關(guān)聯(lián)的 JavaScript 文件將會遵循命名約定規(guī)則,這個(gè)規(guī)則允許該應(yīng)用程序來解析路由并動(dòng)態(tài)地確定每個(gè)內(nèi)容頁需要哪些 JavaScript 文件。

下面的示例應(yīng)用程序的路由表只需要分析出三條路線:

  • 一個(gè)用于根路徑'/'

  • 一個(gè)標(biāo)準(zhǔn)路由路徑,如'/:section/:tree'

  • 包含路由參數(shù)的路由,如'/:section/:tree/:id' 

我決定從 ASP.NET 捆綁中加載 JavaScript 文件,下面的路由配置代碼需要包含一些 applicationConfigurationProvider 引用的代碼,來用于創(chuàng)建保存之前的捆綁信息。捆綁信息將會被解析為 JSON 集。捆綁信息集將會用于返回虛擬的捆綁路徑。此外,JSON 集將被用于跟蹤被加載的捆綁。一旦捆綁被加載,就不需要第二次捆綁了。

有幾件事情需要寫入路由代碼中。首先,每當(dāng)用戶選擇一個(gè)頁面來加載一定功能模塊時(shí),對于模塊綁定的所有 JavaScript 文件需要被下載。例如,當(dāng)用戶選擇客戶模式中的一個(gè)內(nèi)容頁面時(shí),以下的代碼會查看模塊的捆綁是否已經(jīng)通過 JSON _bundles collection 的 isLoaded 屬性被檢查了,并且如果 isLoaded 為 false,則捆綁將會被記載, isLoaded 屬性會被設(shè)置為 true。

當(dāng)確定需要下載哪些模式的捆綁時(shí),有兩件事情需要去加載捆綁:deferred promise 和 RequireJS。deferred promise 可以幫助你異步運(yùn)行函數(shù),當(dāng)它完成執(zhí)行,就會返回。

現(xiàn)在,最后一塊本文之謎是確定從客戶端代碼包中加載的方式。我在以前的文章 CodeProject.com 使用 RequireJS(前面提到的)來動(dòng)態(tài)加載 JavaScript 文件,我使用捆綁來加載 RequireJS。使用 RequireJS“需求”的功能, 我通過捆綁的虛擬路徑進(jìn)入需求功能。事實(shí)證明,需求功能將會加載任何能夠更好執(zhí)行捆綁加載的路徑。

當(dāng)我第一次使用 RequireJS 的路徑來下載捆綁時(shí),我已經(jīng)完成了 RequireJS 和它的所有配置。事實(shí)證明,我能夠去掉這一切,只是簡單地加載 RequireJS 庫并使用它的需求功能。我甚至沒有使用 RequireJS 定義表述來預(yù)安裝我的動(dòng)態(tài)加載控制器。很多試驗(yàn)和錯(cuò)誤之后,我已經(jīng)達(dá)到了本文的目的。我現(xiàn)在可以通過客戶端代碼加載服務(wù)器端的捆綁。

iOS培訓(xùn),Swift培訓(xùn),蘋果開發(fā)培訓(xùn),移動(dòng)開發(fā)培訓(xùn)

, ,  baseSiteUrlPath = $().first().attr( _bundles =.getApplicationVersion = applicationVersion =.getBundle = ( i = ; i < _bundles.Bundles.length; i++ (bundleName.toLowerCase() ==.isLoaded = ( i = ; i < _bundles.Bundles.length; i++ (bundleName.toLowerCase() ==.setIsLoaded = ( i = ; i < _bundles.length; i++ (bundleName.toLowerCase() ===  baseSiteUrlPath +  ++  + rp.tree +  + , ,  path = $location.path().split( parentPath = path[ bundle =  isBundleLoaded =  (isBundleLoaded ==  deferred = baseSiteUrlPath +  ++  + rp.tree +  + , ,  path = $location.path().split( parentPath = path[ bundle =  isBundleLoaded =  (isBundleLoaded ==  deferred = baseSiteUrlPath +  + , ,  bundle = .getBundle( isBundleLoaded = .isLoaded( (isBundleLoaded == .setIsLoaded( deferred =

iOS培訓(xùn),Swift培訓(xùn),蘋果開發(fā)培訓(xùn),移動(dòng)開發(fā)培訓(xùn)