如何在 ASP.NET MVC 中集成 AngularJS(3)

今天来为大家介绍如何在 ASP.NET MVC 中集成 AngularJS 的最后一部分内容。

调试路由表 - HTML 缓存清除

就在我以为示例应用程序完成之后,我意识到,我必须提供两个版本的路由表:一个运行在调试模式的应用程序下和一个运行在发布模式的应用程序下。在调试模式下,JavaScript 文件在未使用压缩功能的情况下会被下载。如果想要调试并在 JavaScript 控制器中设置断点,这是必须的。事实上,路由表的产生版本也出现了一些挑战,由于产生路由代码使用的是 JavaScript 捆绑,但是在 Visual Studio 下,捆绑无法一步一步执行调试,所以我无法调试这些代码。我不得不将一些 console.log 命令和一些 JavaScript 语句警报一起开发并测试来生成路由表。

两个路由版本都包含的事情是:支持 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);  

}]);

测试浏览器缓存

当开发一个 Web 应用程序时,一件你想要做的事情是:测试所有浏览器的缓存和缓存清除功能。你将会想要确保你的应用内容被正确下载并缓存,这些内容会在页面请求之后出现。

你将会对你的内容做很多改变,来重建你的应用,以确保清除缓存和内容被再次下载时新版本号的问题能够解决。

为了测试这一切,我在发布模式下通过 Chrome 浏览器来运行应用,并点击 F12 来打开网络标签。在这里,你可以看见下载你的应用花费了多少时间和来自于服务器的内容,或者是浏览器的缓存。你甚至可以看到捆绑包的下载情况。

最终,你点击你的应用程序的所有页面,你会发现,所有的内容是从浏览器缓存来了,这是单页应用的美丽之处。你的所有内容都会以获取更大的缓存响应时间为结束,唯一要做的点击 web 服务器来从呈现在页面中的 RESTful Web API 来返回 JSON 格式的数据。

其它有趣的点

其它实例应用中有趣的点,还包括执行在服务器端的 .NET 库。对于数据的有效性输入,应用在业务处理中使用了 FluentValidation 库。

FluentValidation 是 .NET 的一个使用流畅的界面和 lambda 表达式建立验证规则的小型验证库。

当试图创建示例应用程序的客户时,客户代码和公司名称为必填项。示例应用程序的业务层管理有效性,使用了 FluentValidation 库验证。通过将一个密集的客户对象传入到 CreateCustomer 方法中,对象上的属性可以通过设置的 FluentValidation 表达式的业务规则被验证。如果该业务对象验证失败,业务层可以从验证库返回错误的集合,并发送错误收集结果到客户端,以便浏览器端错误信息的呈现。

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;
}

下面是定义了客户对象的业务规则类,使用 FluentValidation 库,定义一组 lambda 表达式并创建业务规则和每个验证相关的错误信息。该 FluentValidation 库使用了一组不同的 lambda 表达式来验证业务对象或实体。

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 库的依赖注入的实现。当 Ninject从NuGet 安装时,一个配置文件 NinjectWebCommon.cs 就会为你创建。在这里,你可以告诉 Ninject 库当应用的某些部分被执行时,要创建哪些对象,比如在 Web API 服务中。在下面的 RegisterServices ,我告诉 Ninject 分配客户数据??服务和产品数据服务到他们各自实现的接口中。这就告诉了 Ninject 去哪儿加载匹配的 dll 引用。

namespace CodeProject.Portal.App_Start
{
    using System;
    using System.Web;

    using Microsoft.Web.Infrastructure.DynamicModuleHelper;

    using Ninject;
    using Ninject.Web.Common;

    public static class NinjectWebCommon
    {
        private static readonly Bootstrapper bootstrapper = new Bootstrapper();

        /// <summary>
        /// Starts the application
        /// </summary>
        public static void Start()
        {
            DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
            DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
            bootstrapper.Initialize(CreateKernel);
        }

        /// <summary>
        /// Stops the application.
        /// </summary>
        public static void Stop()
        {
            bootstrapper.ShutDown();
        }

        /// <summary>
        /// Creates the kernel that will manage your application.
        /// </summary>
        /// <returns>The created kernel.</returns>
        private static IKernel CreateKernel()
        {
            var kernel = new StandardKernel();
            try
            {
                kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
                kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();

                RegisterServices(kernel);
                System.Web.Http.GlobalConfiguration.Configuration.DependencyResolver =
                                new Ninject.Web.WebApi.NinjectDependencyResolver(kernel);
                return kernel;
            }
            catch
            {
                kernel.Dispose();
                throw;
            }
        }

        /// <summary>
        /// Load your modules or register your services here!
        /// </summary>
        /// <param name="kernel">The kernel.</param>
        private static void RegisterServices(IKernel kernel)
        {
            kernel.Bind<CodeProject.Interfaces.ICustomerDataService>().
                                    To<CodeProject.Data.EntityFramework.CustomerDataService>();
            kernel.Bind<CodeProject.Interfaces.IProductDataService>().
                                    To<CodeProject.Data.EntityFramework.ProductDataService>();

        }
    }
}

使用 Ninject 数据注解[注入],你可以告诉 Ninject 库何时何地实例化你的对象。在下面的网页 API 服务,客户数据??服务就是由 Ninject 创建的。由于客户业务服务依赖于客户数据的??服务来访问数据,客户数据??服务应该被注入客户业务服务的构造函数中。所有这一切都是通过创建客户数据??的服务接口,然后简单地实现了客户数据??服务接口来完成的。依赖注入是功能强大的,因为它创造应用代码彼此分离的耦合度低的应用层。

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 似乎是一个开始时看起来像挑战的尝试。在试验和失败的每次迭代中,这个挑战变得逐渐变得不那么难。我只是想使所有这些集成起来工作,我不会停止努力。

你可以争论在 ASP.NET 中使用捆绑和缩功能和在 Grunt 与 Gulp 部分使用流行的压缩工具,其各自的优点。如果你是一个无需学习另外技术和工具并且喜欢点击按钮来发布你的 Visual Studio 的微软开发人员,你很可能会想使用 ASP.NET 捆绑功能。我发现这个功能确实是我想要的,它只是花费了我很长的时间来弄清楚如何将它与 AngularJS 集成。

在这些天里,有很多技术可以来写。我以后的一些文章中可能包括 AngularJS 2 和 MEAN 的其余部分,包括 Node.js 的,Express 和 MongoDB。

还有一些包含在最新发布的 Visual Studio 2015 中的一些使用 Apache Cordov 开发的移动应用。这种先进的 HTML 混合的移动应用框架很可能可以和 Apache Cordov 一起工作使用。据说 Ionic 能够使用 HTML 和 AngularJS ,并且可以很容易的建立大规模交互式的移动应用。敬请期待!

文章来源:By Mark J. Caplin

原文链接:http://www.codeproject.com/Articles/1033076/Integrating-AngularJS-with-ASP-NET-MVC

时间: 2024-10-26 13:02:14

如何在 ASP.NET MVC 中集成 AngularJS(3)的相关文章

如何在 ASP.NET MVC 中集成 AngularJS(2)

在如何在 ASP.NET MVC 中集成 AngularJS(1)中,我们介绍了 ASP.NET MVC 捆绑和压缩.应用程序版本自动刷新和工程构建等内容. 下面介绍如何在 ASP.NET MVC 中集成 AngularJS 的第二部分. ASP.NET 捆绑和压缩 CSS 和 JavaScript 的捆绑与压缩功能是 ASP.NET MVC 最流行和有效的特性之一.捆绑和压缩降低了 HTTP 请求和有效载荷的大小,结果是可以更快和更好的执行 ASP.NET MVC 的网站.有许多可以减少 CS

如何在ASP.NET MVC 中获取当前URL、controller、action

一.URL的获取很简单,ASP.NET通用: [1]获取 完整url (协议名+域名+虚拟目录名+文件名+参数) string url=Request.Url.ToString(); [2]获取 虚拟目录名+页面名+参数: string url=Request.RawUrl;(或 string url=Request.Url.PathAndQuery;) [3]获取 虚拟目录名+页面名:string url=HttpContext.Current.Request.Url.AbsolutePath

如何在asp.net mvc中添加自定义的HTML辅助种方法

很久没在博客园发表文章了,今天来总结一下如何在asp.net mvc中添加自定义的HTML辅助方法.我们现在设计这么一个目前,利用自定义的HTML方法来渲染一个普通的img标记.直接进入主题吧: 首先我们先来看一下一个普通的img标签在HTML中的代码: <img src="Content/images/封面.jpg" alt="图片" id="img01" width="500px" height="250p

angular.js的路由和模板在asp.net mvc 中的使用

我们知道angular.js是基于mvc 的一款优秀js框架,它也有一套自己的路由机制,和asp.net mvc 路由不太一样.asp.net mvc 的路由是通过不同的URL到不同的controller然后交给controller去呈现视图.但是在angular.js则是需要提前指定一个module(ng-app),然后去定义路由规则,通过不同的URL,来告诉ng-app 去加载哪个页面.再渲染到ng-view.通过angular.js路由的使用,可以很容易实现页面的局部刷新.更加高效的去创建

在 ASP.NET MVC 中使用 HTTPS (SSL/TLS)

某些安全性较高的网页,如网上支付或用户登陆页面,可能会使用到https(SSL/TLS)来提高安全性.本文介绍了如何在ASP.NET MVC中强制某action使用https和如何进行向https页面的跳转.我们先实现强制一个action使用https.这里写了一个RequireHttpsAttribute,它的作用是将非https连接转换成https连接,这样所有使用了RequireHttps这个filter的controller都会强制使用https连接. 1 using System.We

《Entity Framework 6 Recipes》中文翻译系列 (20) -----第四章 ASP.NET MVC中使用实体框架之在MVC中构建一个CRUD示例

翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 第四章  ASP.NET MVC中使用实体框架 ASP.NET是一个免费的Web框架,它支持3种不同的技术来创建websites(网站)和Web应用:他们分别是,Web Pages,Web Forms,和MVC.虽然MVC是一种非常流行的,有完整的用于软件开发模式理论的技术,但它在ASP.NET中却是一种新的技术. 目前最新的版本是2012年发布的ASP.NET MVC4.自从2008年发布

ASP.NET MVC中jQuery与angularjs混合应用传参并绑定数据

要求是这样子的,在一个列表页中,用户点击详细铵钮,带记录的主键值至另一页.在另一外页中,获取记录数据,然后显示此记录数据在网页上. 先用动图演示: 昨天有分享为ng-click传递参数 <angularjs为ng-click事件传递参数>http://www.cnblogs.com/insus/p/7017737.html 上面仅仅是在ng-click传入一个值,但是在ASP.NET MVC中,还需要把这个值传至另外一个视图中<ASP.NET MVC传递参数(model)>http

如何在ASP.NET Core中实现一个基础的身份认证

注:本文提到的代码示例下载地址> How to achieve a basic authorization in ASP.NET Core 如何在ASP.NET Core中实现一个基础的身份认证 ASP.NET终于可以跨平台了,但是不是我们常用的ASP.NET, 而是叫一个ASP.NET Core的新平台,他可以跨Windows, Linux, OS X等平台来部署你的web应用程序,你可以理解为,这个框架就是ASP.NET的下一个版本,相对于传统ASP.NET程序,它还是有一些不同的地方的,比

如何在asp.net mvc3中使用HttpStatusCode

下载了asp.net mvc 4的源码看了看,没怎么看清楚.不过个人觉得MVC4 beta中Web API这个是比较不错的,虽然说它是往传统回归. web api最好的莫过于它更加适合使用jquery的ajax调用. 我这里主要给大家说明下如何在asp.net mvc 3中借鉴Web API的特性来让AJAX调用更加酷. 首先给大家看个例子,传统的asp.net mvc 3中异步调用的Response: Action如下: 相应的jquery ajax请求代码(只是简单的代码,): 我们来运行看