如何在 ASP.NET MVC 中集成 AngularJS(3)
今天來為大家介紹如何在 ASP.NET MVC 中集成 AngularJS 的最后一部分內(nèi)容。
調(diào)試路由表 - HTML 緩存清除
就在我以為示例應(yīng)用程序完成之后,我意識(shí)到,我必須提供兩個(gè)版本的路由表:一個(gè)運(yùn)行在調(diào)試模式的應(yīng)用程序下和一個(gè)運(yùn)行在發(fā)布模式的應(yīng)用程序下。在調(diào)試模式下,JavaScript 文件在未使用壓縮功能的情況下會(huì)被下載。如果想要調(diào)試并在 JavaScript?控制器中設(shè)置斷點(diǎn),這是必須的。事實(shí)上,路由表的產(chǎn)生版本也出現(xiàn)了一些挑戰(zhàn),由于產(chǎn)生路由代碼使用的是 JavaScript 捆綁,但是在 Visual Studio 下,捆綁無法一步一步執(zhí)行調(diào)試,所以我無法調(diào)試這些代碼。我不得不將一些 console.log 命令和一些 JavaScript 語(yǔ)句警報(bào)一起開發(fā)并測(cè)試來生成路由表。
兩個(gè)路由版本都包含的事情是:支持 HTML 文件的緩存,就像捆綁和 JavaScript,你還需要提供一個(gè)附屬在 HTML Angular 視圖上的序列號(hào)。在調(diào)試和生成路由代碼兩種情況下,嵌入版本號(hào)將會(huì)從 applicationConfigurationProvder?中推出并附屬在緩存的 HTML 路徑中。
// CodeProjectRouting-debug.js
angular.module("codeProject").config(
['$routeProvider', '$locationProvider', 'applicationConfigurationProvider',
? ? function ($routeProvider, $locationProvider, applicationConfigurationProvider) {
? ? this.getApplicationVersion = function () {
? ? ? ? var applicationVersion = applicationConfigurationProvider.getVersion();
? ? ? ? return applicationVersion;
? ? }
? ? var baseSiteUrlPath = $("base").first().attr("href");
? ?
? ? $routeProvider.when('/:section/:tree',
? ? {
? ? ? ? templateUrl: function (rp) { return baseSiteUrlPath + 'views/' +?
? ? ? ? ? ? ? ? ? ? ?rp.section + '/' + rp.tree + '.html?v=' + this.getApplicationVersion(); },
? ? ? ? resolve: {
? ? ? ? ? ? load: ['$q', '$rootScope', '$location', function ($q, $rootScope, $location) {
? ? ? ? ? ? ? ? var path = $location.path().split("/");
? ? ? ? ? ? ? ? var directory = path[1];
? ? ? ? ? ? ? ? var controllerName = path[2];
? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? var controllerToLoad = "Views/" + directory + "/" +?
? ? ? ? ? ? ? ? ? ? controllerName + "Controller.js?v=" + this.getApplicationVersion();
? ? ? ? ? ? ? ? var deferred = $q.defer();
? ? ? ? ? ? ? ? require([controllerToLoad], function () {
? ? ? ? ? ? ? ? ? ? $rootScope.$apply(function () {
? ? ? ? ? ? ? ? ? ? ? ? deferred.resolve();
? ? ? ? ? ? ? ? ? ? });
? ? ? ? ? ? ? ? });
? ? ? ? ? ? ? ? return deferred.promise;
? ? ? ? ? ? ??
? ? ? ? ? ? }]
? ? ? ? }
? ? });
? ? $routeProvider.when('/:section/:tree/:id',
? ? {
? ? ? ? templateUrl: function (rp) { return baseSiteUrlPath + 'views/' +?
? ? ? ? ? ? ? ? ? ? ?rp.section + '/' + rp.tree + '.html?v=' + this.getApplicationVersion(); },
? ? ? ? resolve: {
? ? ? ? ? ? load: ['$q', '$rootScope', '$location', function ($q, $rootScope, $location) {
? ? ? ? ? ? ? ? var path = $location.path().split("/");
? ? ? ? ? ? ? ? var directory = path[1];
? ? ? ? ? ? ? ? var controllerName = path[2];
? ? ? ? ? ? ? ? var controllerToLoad = "Views/" + directory + "/" + controllerName +?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?"Controller.js?v=" + this.getApplicationVersion();
? ? ? ? ? ? ? ? var deferred = $q.defer();
? ? ? ? ? ? ? ? require([controllerToLoad], function () {
? ? ? ? ? ? ? ? ? ? $rootScope.$apply(function () {
? ? ? ? ? ? ? ? ? ? ? ? deferred.resolve();
? ? ? ? ? ? ? ? ? ? });
? ? ? ? ? ? ? ? });
? ? ? ? ? ? ? ? return deferred.promise;
? ? ? ? ? ? }]
? ? ? ? }
? ? });
? ? $routeProvider.when('/',
? ? {
? ? ? ? templateUrl: function (rp) { return baseSiteUrlPath + 'views/Home/Index.html?v=' +?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?this.getApplicationVersion(); },
? ? ? ? resolve: {
? ? ? ? ? ? load: ['$q', '$rootScope', '$location', function ($q, $rootScope, $location) {
? ? ? ? ? ? ? ? var controllerToLoad = "Views/Home/IndexController.js?v=" +?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? this.getApplicationVersion();
? ? ? ? ? ? ? ? var deferred = $q.defer();
? ? ? ? ? ? ? ? require([controllerToLoad], function () {
? ? ? ? ? ? ? ? ? ? $rootScope.$apply(function () {
? ? ? ? ? ? ? ? ? ? ? ? deferred.resolve();
? ? ? ? ? ? ? ? ? ? });
? ? ? ? ? ? ? ? });
? ? ? ? ? ? ? ? return deferred.promise;
? ? ? ? ? ? }]
? ? ? ? }
? ? });
? ? $locationProvider.html5Mode(true); ?
}]);
測(cè)試瀏覽器緩存
當(dāng)開發(fā)一個(gè) Web 應(yīng)用程序時(shí),一件你想要做的事情是:測(cè)試所有瀏覽器的緩存和緩存清除功能。你將會(huì)想要確保你的應(yīng)用內(nèi)容被正確下載并緩存,這些內(nèi)容會(huì)在頁(yè)面請(qǐng)求之后出現(xiàn)。
你將會(huì)對(duì)你的內(nèi)容做很多改變,來重建你的應(yīng)用,以確保清除緩存和內(nèi)容被再次下載時(shí)新版本號(hào)的問題能夠解決。
為了測(cè)試這一切,我在發(fā)布模式下通過 Chrome 瀏覽器來運(yùn)行應(yīng)用,并點(diǎn)擊 F12 來打開網(wǎng)絡(luò)標(biāo)簽。在這里,你可以看見下載你的應(yīng)用花費(fèi)了多少時(shí)間和來自于服務(wù)器的內(nèi)容,或者是瀏覽器的緩存。你甚至可以看到捆綁包的下載情況。
最終,你點(diǎn)擊你的應(yīng)用程序的所有頁(yè)面,你會(huì)發(fā)現(xiàn),所有的內(nèi)容是從瀏覽器緩存來了,這是單頁(yè)應(yīng)用的美麗之處。你的所有內(nèi)容都會(huì)以獲取更大的緩存響應(yīng)時(shí)間為結(jié)束,唯一要做的點(diǎn)擊 web 服務(wù)器來從呈現(xiàn)在頁(yè)面中的 RESTful Web API 來返回 JSON 格式的數(shù)據(jù)。
?
其它有趣的點(diǎn)?
其它實(shí)例應(yīng)用中有趣的點(diǎn),還包括執(zhí)行在服務(wù)器端的 .NET 庫(kù)。對(duì)于數(shù)據(jù)的有效性輸入,應(yīng)用在業(yè)務(wù)處理中使用了 FluentValidation 庫(kù)。?
FluentValidation 是 .NET 的一個(gè)使用流暢的界面和 lambda 表達(dá)式建立驗(yàn)證規(guī)則的小型驗(yàn)證庫(kù)。
當(dāng)試圖創(chuàng)建示例應(yīng)用程序的客戶時(shí),客戶代碼和公司名稱為必填項(xiàng)。示例應(yīng)用程序的業(yè)務(wù)層管理有效性,使用了 FluentValidation 庫(kù)驗(yàn)證。通過將一個(gè)密集的客戶對(duì)象傳入到?CreateCustomer?方法中,對(duì)象上的屬性可以通過設(shè)置的 FluentValidation?表達(dá)式的業(yè)務(wù)規(guī)則被驗(yàn)證。如果該業(yè)務(wù)對(duì)象驗(yàn)證失敗,業(yè)務(wù)層可以從驗(yàn)證庫(kù)返回錯(cuò)誤的集合,并發(fā)送錯(cuò)誤收集結(jié)果到客戶端,以便瀏覽器端錯(cuò)誤信息的呈現(xiàn)。
public Customer CreateCustomer(Customer customer, out TransactionalInformation transaction)
{
? ? ?transaction = new TransactionalInformation();
? ? ?try
? ? ?{
? ? ? ? ?CustomerBusinessRules customerBusinessRules = new CustomerBusinessRules();
? ? ? ? ?ValidationResult results = customerBusinessRules.Validate(customer);
? ? ? ? ?bool validationSucceeded = results.IsValid;
? ? ? ? ?IList<ValidationFailure> failures = results.Errors;
? ? ? ? ?if (validationSucceeded == false)
? ? ? ? ?{
? ? ? ? ? ? ?transaction = ValidationErrors.PopulateValidationErrors(failures);
? ? ? ? ? ? ?return customer;
? ? ? ? ?}
? ? ? ? ?_customerDataService.CreateSession();
? ? ? ? ?_customerDataService.BeginTransaction();
? ? ? ? ?_customerDataService.CreateCustomer(customer);
? ? ? ? ?_customerDataService.CommitTransaction(true);
? ? ? ? ?transaction.ReturnStatus = true;
? ? ? ? ?transaction.ReturnMessage.Add("Customer successfully created.");
? ? }
? ? catch (Exception ex)
? ? {
? ? ? ? ?string errorMessage = ex.Message;
? ? ? ? ?transaction.ReturnMessage.Add(errorMessage);
? ? ? ? ?transaction.ReturnStatus = false;
? ? }
? ? finally
? ? {
? ? ? ? _customerDataService.CloseSession();
? ? }
? ? return customer;
}
下面是定義了客戶對(duì)象的業(yè)務(wù)規(guī)則類,使用 FluentValidation 庫(kù),定義一組 lambda 表達(dá)式并創(chuàng)建業(yè)務(wù)規(guī)則和每個(gè)驗(yàn)證相關(guān)的錯(cuò)誤信息。該 FluentValidation 庫(kù)使用了一組不同的 lambda 表達(dá)式來驗(yàn)證業(yè)務(wù)對(duì)象或?qū)嶓w。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using FluentValidation;
using CodeProject.Business.Entities;
using System.Configuration;
using CodeProject.Interfaces;
namespace CodeProject.Business
{
? ? public class CustomerBusinessRules : AbstractValidator<Customer>
? ? {
? ? ? ? public CustomerBusinessRules()
? ? ? ? { ? ? ??
? ? ? ? ? ? RuleFor(c => c.CompanyName).NotEmpty().WithMessage("Company Name is required.");
? ? ? ? ? ? RuleFor(c => c.CustomerCode).NotEmpty().WithMessage("Customer Code is required."); ??
? ? ? ? }
? ? }
}
在示例應(yīng)用程序中另一個(gè)值得注意的點(diǎn),是使用 Ninject 庫(kù)的依賴注入的實(shí)現(xiàn)。當(dāng) Ninject從NuGet?安裝時(shí),一個(gè)配置文件 NinjectWebCommon.cs 就會(huì)為你創(chuàng)建。在這里,你可以告訴 Ninject 庫(kù)當(dāng)應(yīng)用的某些部分被執(zhí)行時(shí),要?jiǎng)?chuàng)建哪些對(duì)象,比如在 Web API 服務(wù)中。在下面的?RegisterServices?中,我告訴 Ninject 分配客戶數(shù)據(jù)服務(wù)和產(chǎn)品數(shù)據(jù)服務(wù)到他們各自實(shí)現(xiàn)的接口中。這就告訴了 Ninject 去哪兒加載匹配的 dll 引用。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using CodeProject.Portal.Models;
using CodeProject.Business.Entities;
using CodeProject.Business;
using CodeProject.Interfaces;
using Ninject;
namespace CodeProject.Portal.WebApiControllers
{
? ? [RoutePrefix("api/CustomerService")]
? ? public class CustomerServiceController : ApiController
? ? {
? ? ? ? [Inject]
? ? ? ? public ICustomerDataService _customerDataService { get; set; }
? ? ? ? /// <summary>
? ? ? ? /// Create Customer
? ? ? ? /// </summary>
? ? ? ? /// <param name="request"></param>
? ? ? ? /// <param name="customerViewModel"></param>
? ? ? ? /// <returns></returns>
? ? ? ? [Route("CreateCustomer")] ? ??
? ? ? ? [HttpPost]
? ? ? ? public HttpResponseMessage CreateCustomer(HttpRequestMessage request,?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?[FromBody] CustomerViewModel customerViewModel)
? ? ? ? {
? ? ? ? ? ? TransactionalInformation transaction;
? ? ? ? ? ? Customer customer = new Customer();
? ? ? ? ? ? customer.CompanyName = customerViewModel.CompanyName;
? ? ? ? ? ? customer.ContactName = customerViewModel.ContactName;
? ? ? ? ? ? customer.ContactTitle = customerViewModel.ContactTitle;
? ? ? ? ? ? customer.CustomerCode = customerViewModel.CustomerCode;
? ? ? ? ? ? customer.Address = customerViewModel.Address;
? ? ? ? ? ? customer.City = customerViewModel.City;
? ? ? ? ? ? customer.Region = customerViewModel.Region;
? ? ? ? ? ? customer.PostalCode = customerViewModel.PostalCode;
? ? ? ? ? ? customer.Country = customerViewModel.Country;
? ? ? ? ? ? customer.PhoneNumber = customerViewModel.PhoneNumber;
? ? ? ? ? ? customer.MobileNumber = customerViewModel.MobileNumber;
? ? ? ? ? ? CustomerBusinessService customerBusinessService =?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? new CustomerBusinessService(_customerDataService);
? ? ? ? ? ? customerBusinessService.CreateCustomer(customer, out transaction);
? ? ? ? ? ? if (transaction.ReturnStatus == false)
? ? ? ? ? ? { ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? customerViewModel.ReturnStatus = false;
? ? ? ? ? ? ? ? customerViewModel.ReturnMessage = transaction.ReturnMessage;
? ? ? ? ? ? ? ? customerViewModel.ValidationErrors = transaction.ValidationErrors;
? ? ? ? ? ? ? ? var responseError = Request.CreateResponse<CustomerViewModel>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? (HttpStatusCode.BadRequest, customerViewModel);
? ? ? ? ? ? ? ? return responseError;
? ? ? ? ? ? ??
? ? ? ? ? ? }
? ? ? ? ? ? customerViewModel.CustomerID = customer.CustomerID;
? ? ? ? ? ? customerViewModel.ReturnStatus = true;
? ? ? ? ? ? customerViewModel.ReturnMessage = transaction.ReturnMessage;
? ? ? ? ? ? var response = Request.CreateResponse<CustomerViewModel>
? ? ? ? ? ? ? ? ? ? ? ? ? ?(HttpStatusCode.OK, customerViewModel);
? ? ? ? ? ? return response;
? ? ? ? }
使用 Ninject 數(shù)據(jù)注解[注入],你可以告訴 Ninject 庫(kù)何時(shí)何地實(shí)例化你的對(duì)象。在下面的網(wǎng)頁(yè) API 服務(wù),客戶數(shù)據(jù)服務(wù)就是由 Ninject 創(chuàng)建的。由于客戶業(yè)務(wù)服務(wù)依賴于客戶數(shù)據(jù)的服務(wù)來訪問數(shù)據(jù),客戶數(shù)據(jù)服務(wù)應(yīng)該被注入客戶業(yè)務(wù)服務(wù)的構(gòu)造函數(shù)中。所有這一切都是通過創(chuàng)建客戶數(shù)據(jù)的服務(wù)接口,然后簡(jiǎn)單地實(shí)現(xiàn)了客戶數(shù)據(jù)服務(wù)接口來完成的。依賴注入是功能強(qiáng)大的,因?yàn)樗鼊?chuàng)造應(yīng)用代碼彼此分離的耦合度低的應(yīng)用層。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using CodeProject.Portal.Models;
using CodeProject.Business.Entities;
using CodeProject.Business;
using CodeProject.Interfaces;
using Ninject;
namespace CodeProject.Portal.WebApiControllers
{
? ? [RoutePrefix("api/CustomerService")]
? ? public class CustomerServiceController : ApiController
? ? {
? ? ? ? [Inject]
? ? ? ? public ICustomerDataService _customerDataService { get; set; }
? ? ? ? /// <summary>
? ? ? ? /// Create Customer
? ? ? ? /// </summary>
? ? ? ? /// <param name="request"></param>
? ? ? ? /// <param name="customerViewModel"></param>
? ? ? ? /// <returns></returns>
? ? ? ? [Route("CreateCustomer")] ? ??
? ? ? ? [HttpPost]
? ? ? ? public HttpResponseMessage CreateCustomer(HttpRequestMessage request,?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?[FromBody] CustomerViewModel customerViewModel)
? ? ? ? {
? ? ? ? ? ? TransactionalInformation transaction;
? ? ? ? ? ? Customer customer = new Customer();
? ? ? ? ? ? customer.CompanyName = customerViewModel.CompanyName;
? ? ? ? ? ? customer.ContactName = customerViewModel.ContactName;
? ? ? ? ? ? customer.ContactTitle = customerViewModel.ContactTitle;
? ? ? ? ? ? customer.CustomerCode = customerViewModel.CustomerCode;
? ? ? ? ? ? customer.Address = customerViewModel.Address;
? ? ? ? ? ? customer.City = customerViewModel.City;
? ? ? ? ? ? customer.Region = customerViewModel.Region;
? ? ? ? ? ? customer.PostalCode = customerViewModel.PostalCode;
? ? ? ? ? ? customer.Country = customerViewModel.Country;
? ? ? ? ? ? customer.PhoneNumber = customerViewModel.PhoneNumber;
? ? ? ? ? ? customer.MobileNumber = customerViewModel.MobileNumber;
? ? ? ? ? ? CustomerBusinessService customerBusinessService =?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? new CustomerBusinessService(_customerDataService);
? ? ? ? ? ? customerBusinessService.CreateCustomer(customer, out transaction);
? ? ? ? ? ? if (transaction.ReturnStatus == false)
? ? ? ? ? ? { ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? customerViewModel.ReturnStatus = false;
? ? ? ? ? ? ? ? customerViewModel.ReturnMessage = transaction.ReturnMessage;
? ? ? ? ? ? ? ? customerViewModel.ValidationErrors = transaction.ValidationErrors;
? ? ? ? ? ? ? ? var responseError = Request.CreateResponse<CustomerViewModel>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? (HttpStatusCode.BadRequest, customerViewModel);
? ? ? ? ? ? ? ? return responseError;
? ? ? ? ? ? ??
? ? ? ? ? ? }
? ? ? ? ? ? customerViewModel.CustomerID = customer.CustomerID;
? ? ? ? ? ? customerViewModel.ReturnStatus = true;
? ? ? ? ? ? customerViewModel.ReturnMessage = transaction.ReturnMessage;
? ? ? ? ? ? var response = Request.CreateResponse<CustomerViewModel>
? ? ? ? ? ? ? ? ? ? ? ? ? ?(HttpStatusCode.OK, customerViewModel);
? ? ? ? ? ? return response;
? ? ? ? }
結(jié)論
在 ASP.NET MVC 和 ASP.NET 捆綁中集成 AngularJS 似乎是一個(gè)開始時(shí)看起來像挑戰(zhàn)的嘗試。在試驗(yàn)和失敗的每次迭代中,這個(gè)挑戰(zhàn)變得逐漸變得不那么難。我只是想使所有這些集成起來工作,我不會(huì)停止努力。
你可以爭(zhēng)論在 ASP.NET 中使用捆綁和縮功能和在 Grunt 與 Gulp 部分使用流行的壓縮工具,其各自的優(yōu)點(diǎn)。如果你是一個(gè)無需學(xué)習(xí)另外技術(shù)和工具并且喜歡點(diǎn)擊按鈕來發(fā)布你的 Visual Studio 的微軟開發(fā)人員,你很可能會(huì)想使用 ASP.NET 捆綁功能。我發(fā)現(xiàn)這個(gè)功能確實(shí)是我想要的,它只是花費(fèi)了我很長(zhǎng)的時(shí)間來弄清楚如何將它與 AngularJS 集成。
在這些天里,有很多技術(shù)可以來寫。我以后的一些文章中可能包括 AngularJS 2 和 MEAN?的其余部分,包括 Node.js 的,Express 和 MongoDB。
還有一些包含在最新發(fā)布的 Visual Studio 2015 中的一些使用 Apache Cordov 開發(fā)的移動(dòng)應(yīng)用。這種先進(jìn)的 HTML 混合的移動(dòng)應(yīng)用框架很可能可以和 Apache Cordov 一起工作使用。據(jù)說 Ionic 能夠使用 HTML 和 AngularJS ,并且可以很容易的建立大規(guī)模交互式的移動(dòng)應(yīng)用。敬請(qǐng)期待!?
文章來源:By?Mark J. Caplin?
原文鏈接:http://www.codeproject.com/Articles/1033076/Integrating-AngularJS-with-ASP-NET-MVC
.NET社區(qū)新聞,深度好文,微信中搜索dotNET跨平臺(tái)或掃描二維碼關(guān)注
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)總結(jié)
以上是生活随笔為你收集整理的如何在 ASP.NET MVC 中集成 AngularJS(3)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何在 ASP.NET MVC 中集成
- 下一篇: IBM® Bluemix 上运行ASP.