如何在 ASP.NET MVC 中集成 AngularJS(3)
今天來為大家介紹如何在 ASP.NET MVC 中集成 AngularJS 的最后一部分內容。
調試路由表 - HTML 緩存清除
就在我以為示例應用程序完成之后,我意識到,我必須提供兩個版本的路由表:一個運行在調試模式的應用程序下和一個運行在發(fā)布模式的應用程序下。在調試模式下,JavaScript 文件在未使用壓縮功能的情況下會被下載。如果想要調試并在 JavaScript?控制器中設置斷點,這是必須的。事實上,路由表的產(chǎn)生版本也出現(xiàn)了一些挑戰(zhàn),由于產(chǎn)生路由代碼使用的是 JavaScript 捆綁,但是在 Visual Studio 下,捆綁無法一步一步執(zhí)行調試,所以我無法調試這些代碼。我不得不將一些 console.log 命令和一些 JavaScript 語句警報一起開發(fā)并測試來生成路由表。
兩個路由版本都包含的事情是:支持 HTML 文件的緩存,就像捆綁和 JavaScript,你還需要提供一個附屬在 HTML Angular 視圖上的序列號。在調試和生成路由代碼兩種情況下,嵌入版本號將會從 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); ?
}]);
測試瀏覽器緩存
當開發(fā)一個 Web 應用程序時,一件你想要做的事情是:測試所有瀏覽器的緩存和緩存清除功能。你將會想要確保你的應用內容被正確下載并緩存,這些內容會在頁面請求之后出現(xiàn)。
你將會對你的內容做很多改變,來重建你的應用,以確保清除緩存和內容被再次下載時新版本號的問題能夠解決。
為了測試這一切,我在發(fā)布模式下通過 Chrome 瀏覽器來運行應用,并點擊 F12 來打開網(wǎng)絡標簽。在這里,你可以看見下載你的應用花費了多少時間和來自于服務器的內容,或者是瀏覽器的緩存。你甚至可以看到捆綁包的下載情況。
最終,你點擊你的應用程序的所有頁面,你會發(fā)現(xiàn),所有的內容是從瀏覽器緩存來了,這是單頁應用的美麗之處。你的所有內容都會以獲取更大的緩存響應時間為結束,唯一要做的點擊 web 服務器來從呈現(xiàn)在頁面中的 RESTful Web API 來返回 JSON 格式的數(shù)據(jù)。
?
其它有趣的點?
其它實例應用中有趣的點,還包括執(zhí)行在服務器端的 .NET 庫。對于數(shù)據(jù)的有效性輸入,應用在業(yè)務處理中使用了 FluentValidation 庫。?
FluentValidation 是 .NET 的一個使用流暢的界面和 lambda 表達式建立驗證規(guī)則的小型驗證庫。
當試圖創(chuàng)建示例應用程序的客戶時,客戶代碼和公司名稱為必填項。示例應用程序的業(yè)務層管理有效性,使用了 FluentValidation 庫驗證。通過將一個密集的客戶對象傳入到?CreateCustomer?方法中,對象上的屬性可以通過設置的 FluentValidation?表達式的業(yè)務規(guī)則被驗證。如果該業(yè)務對象驗證失敗,業(yè)務層可以從驗證庫返回錯誤的集合,并發(fā)送錯誤收集結果到客戶端,以便瀏覽器端錯誤信息的呈現(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;
}
下面是定義了客戶對象的業(yè)務規(guī)則類,使用 FluentValidation 庫,定義一組 lambda 表達式并創(chuàng)建業(yè)務規(guī)則和每個驗證相關的錯誤信息。該 FluentValidation 庫使用了一組不同的 lambda 表達式來驗證業(yè)務對象或實體。
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."); ??
? ? ? ? }
? ? }
}
在示例應用程序中另一個值得注意的點,是使用 Ninject 庫的依賴注入的實現(xiàn)。當 Ninject從NuGet?安裝時,一個配置文件 NinjectWebCommon.cs 就會為你創(chuàng)建。在這里,你可以告訴 Ninject 庫當應用的某些部分被執(zhí)行時,要創(chuàng)建哪些對象,比如在 Web API 服務中。在下面的?RegisterServices?中,我告訴 Ninject 分配客戶數(shù)據(jù)服務和產(chǎn)品數(shù)據(jù)服務到他們各自實現(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 庫何時何地實例化你的對象。在下面的網(wǎng)頁 API 服務,客戶數(shù)據(jù)服務就是由 Ninject 創(chuàng)建的。由于客戶業(yè)務服務依賴于客戶數(shù)據(jù)的服務來訪問數(shù)據(jù),客戶數(shù)據(jù)服務應該被注入客戶業(yè)務服務的構造函數(shù)中。所有這一切都是通過創(chuàng)建客戶數(shù)據(jù)的服務接口,然后簡單地實現(xiàn)了客戶數(shù)據(jù)服務接口來完成的。依賴注入是功能強大的,因為它創(chuà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;
? ? ? ? }
結論
在 ASP.NET MVC 和 ASP.NET 捆綁中集成 AngularJS 似乎是一個開始時看起來像挑戰(zhàn)的嘗試。在試驗和失敗的每次迭代中,這個挑戰(zhàn)變得逐漸變得不那么難。我只是想使所有這些集成起來工作,我不會停止努力。
你可以爭論在 ASP.NET 中使用捆綁和縮功能和在 Grunt 與 Gulp 部分使用流行的壓縮工具,其各自的優(yōu)點。如果你是一個無需學習另外技術和工具并且喜歡點擊按鈕來發(fā)布你的 Visual Studio 的微軟開發(fā)人員,你很可能會想使用 ASP.NET 捆綁功能。我發(fā)現(xiàn)這個功能確實是我想要的,它只是花費了我很長的時間來弄清楚如何將它與 AngularJS 集成。
在這些天里,有很多技術可以來寫。我以后的一些文章中可能包括 AngularJS 2 和 MEAN?的其余部分,包括 Node.js 的,Express 和 MongoDB。
還有一些包含在最新發(fā)布的 Visual Studio 2015 中的一些使用 Apache Cordov 開發(fā)的移動應用。這種先進的 HTML 混合的移動應用框架很可能可以和 Apache Cordov 一起工作使用。據(jù)說 Ionic 能夠使用 HTML 和 AngularJS ,并且可以很容易的建立大規(guī)模交互式的移動應用。敬請期待!?
文章來源:By?Mark J. Caplin?
原文鏈接:http://www.codeproject.com/Articles/1033076/Integrating-AngularJS-with-ASP-NET-MVC
.NET社區(qū)新聞,深度好文,微信中搜索dotNET跨平臺或掃描二維碼關注
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅持創(chuàng)作打卡瓜分現(xiàn)金大獎總結
以上是生活随笔為你收集整理的如何在 ASP.NET MVC 中集成 AngularJS(3)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何在 ASP.NET MVC 中集成
- 下一篇: IBM® Bluemix 上运行ASP.