AngularJS 和 WebAPI 入门






4.83/5 (20投票s)
本文介绍了 AngularJS 的基本架构以及如何将其连接到 WebAPI。
必备组件
- Javascript
- C#
- MVC
- Visual Studio 2013 (已安装)
什么是 AngularJS? (维基)
AngularJS,通常简称为 Angular,是一个由 Google 以及个人开发者和公司社区维护的开源 Web 应用程序框架,旨在解决开发单页应用程序时遇到的许多挑战。其目标是通过提供客户端模型-视图-控制器 (MVC) 架构的框架来简化此类应用程序的开发和测试。
Angular 是您项目的合适工具吗?
- 您是否有很多前端数据操作?
- 每页的记录数是否少于 2000 条?
- 您想构建一个单页应用程序吗?
如果您的答案是肯定的,那么我鼓励您使用 Angular。 MVC 架构可帮助您编写清晰、可维护且可重用的代码。 当记录数超过 2000 条时,Angular 运行会变慢,因此不建议使用它。
Angular 在哪里运行?
由于 Angular 是一个 JavaScript 框架,因此它在客户端运行。 我再说一遍,它在客户端运行,不 在服务器上运行。
WebAPI 呢?
到目前为止发生了什么。
- 客户端请求您的网站
- 客户端获取相关的 HTML、CSS、JavaScript (包括 Angular)
- Angular 现在正在客户端运行,监听并响应事件(点击、状态更改等)。
此时一切都很美好,但我们忘了提及从数据库获取数据的那一小部分。 那正是 WebAPI 的工作! 由于 Angular 是一个 JavaScript 框架,自然而然地,读取数据的最方便的方式就是 JavaScript 对象(JSON,**J**ava**S**cript **O**bject **N**otation)。 WebAPI 是一个 RESTful Web 服务,碰巧返回 JSON(真幸运!),它运行在服务器上并等待 HTTP 请求(POST、GET 等)。 它的工作是从数据库中获取数据并将其作为 JSON 返回给客户端(记住 Angular 需要 JSON 格式的数据)。
HTTP POST/PUT 和 GET
- 当您想从数据库读取(选择)数据时,请使用“GET”。
- 当您想向数据库写入(插入、更新)数据时,请使用“POST/PUT”。
POST 和 GET 安全性
POST 不比 GET 更安全。 两者对攻击者来说都是可见的……
整体图景
红色箭头代表第一阶段。
- 如前所述,用户访问您的网站 (1)
- 您的服务器响应相关的 HTML、CSS 和 JavaScript (2)
- Angular 开始在客户端运行
蓝色箭头代表第二阶段
- Angular 意识到它需要数据库中的数据,因此它要求 WebAPI 提供这些数据 (3)
- WebAPI 访问数据库并请求数据 (4)
- 数据库返回数据 (5)
- WebAPI 将数据重新格式化为 JSON 并将其发送给 Angular (6)
动手实践 Angular!
在 Visual Studio 2013 中,点击
- 点击“文件”
- 新建 => “项目”
- 选择“Web” => “ASP.NET Web 应用程序” => “确定”
- 选择“Empty” => “更改身份验证”并移除身份验证
- 点击“确定”
现在,创建所有文件和目录以拥有如下的项目结构。
下载以下库 jQuery、Angular、Ui-Router、Bootstrap(非必需)并将它们添加到项目中,如下图所示。
请注意,我们有一个名为 Index 的 HTML 文件,它将充当 ASP.NET 中的 MasterPage。 因此,Index.html 将包含所有 JavaScript 和 CSS 引用。 那么,让我们深入了解 Index.html。
/Index.html
<!DOCTYPE html> <html ng-app="app"> <!-- this tell Angular to run --> <head> <title>Angular + WebAPI</title> <script src="./Scripts/jquery.js"></script> <script src="./Scripts/angular.js"></script> <script src="./Scripts/angular-ui-router.js"></script> <script src="./App/app.js"></script> <script src="./App/controllers.js"></script> <script src="./Scripts/bootstrap.min.js"></script> <link rel="stylesheet" href="./Style/CSS/bootstrap.css" /> <link rel="stylesheet" href="./Style/CSS/style.css" /> </head> <body> <nav class="navbar navbar-default"> <div class="container"> <ul class="nav navbar-nav"> <li> <a href="#/"> Home </a> </li> <li> <a href="#/movies"> Movies </a> </li> </ul> </div> </nav> <div class="container"> <!-- Note the below ui-view attribute, not the id. The content of the div will be replaces by the view that is stated inside app.js --> <div id="ui-view" ui-view> </div> </div> </body> </html>
/App/app.js
// Declares how the application should be bootstrapped. See: http://docs.angularjs.org/guide/module angular.module('app', [ // Dependency Inject Goes inside this array 'ui.router', // we inject/load ui-router for routing 'app.controllers', // we inject/load the controllers ] ) .config(['$stateProvider', function ($stateProvider) { // UI States, URL Routing & Mapping. For more info see: https://github.com/angular-ui/ui-router // our routers, self explanatory $stateProvider .state('home', { url: '/', templateUrl: './View/Home.html' }) .state('movies', { url: '/movies', templateUrl: './View/Movies.html', controller: 'MoviesController' }) .state('otherwise', { url: '*path', templateUrl: '/View/Error.html', controller: 'ErrorCtrl' }); }] );
/App/controllers.js
//we initialize the module name to 'app.controllers' // app.js will search for a module called 'app.controllers' and will find this one and inject it angular.module('app.controllers', []) .controller('MoviesController', function ($scope) { // this will do for now });
/View/Movies.html
<div class="row"> <h2>Movies</h2> </div> <div class="row"> <table class="table"> <thead> <tr> <th>Id</th> <th>Name</th> <th>Director</th> </tr> </thead> <tbody> <tr> <td> 1 </td> <td> Fight Club </td> <td> David Fincher </td> </tr> <tr> <td> 2 </td> <td> Into The Wild </td> <td> Sean Penn </td> </tr> </tbody> </table> </div>
将项目添加到 IIS
按 Windows 键并搜索“IIS”,即 Internet Information Service。如果您没有它,可能需要安装它。
- 展开“站点”
- 右键单击“Default Web Site” => 然后选择“添加应用程序”
- 在“别名”中,输入“angular”
- 将物理路径指向您的项目(而不是解决方案)目录。
X:\ CodeProjectAngular\CodeProjectAngular
打开您喜欢的浏览器并转到
https:///angular/#/movies
正如您可能注意到的,电影数据是硬编码在视图中的。 接下来,我们将从视图中移除硬编码,并将其放在控制器中。
/App/controllers.js
angular.module('app.controllers', []) .controller('MoviesController', function ($scope) { $scope.movies = [ { Id: 1, Name: "Fight Club",Director: "David Fincher" }, { Id: 2, Name: "Into The Wild", Director: "Sean Penn" }, { Id: 3, Name: "Dancer in the Dark", Director:"Lars von Trier " } ]; });
$scope 是怎么回事?
Angular 不仅仅是 MVC,它也是 MVVM。 任何以‘$’开头的都是 Angular 的内部对象。 因此,$scope 是一个内部对象,您可能想知道它有什么作用? 将 $scope 想象成一个公共的静态类,它只有一个实例,如果您在一个地方更改它,其他所有地方都会被更改。 由于控制器在 $scope 内读/写,而视图也在同一个 $scope 内读/写,因此任何更改都将对两者都可用。
正如您所注意到的,视图和 $scope 之间存在双向绑定,控制器和 $scope 之间也存在双向绑定。 因此,当 $scope 更新时,控制器和视图都会更新。
如何在视图中读取 $scope
在控制器中,我们初始化了 $scope.movies 作为一个数组并填充了它。 在视图中,我们想遍历该数组并渲染对象。 Angular 扩展了 HTML,允许我们在 HTML 中编写循环函数。 在视图中访问 $scope 时,我们会省略 $scope。 所以要访问视图中的 $scope.movies,我们只需说“movies”。
/Views/Movies.html
<div class="row"> <h2>Movies</h2> </div> <div class="row"> <table class="table"> <thead> <tr> <th>Id</th> <th>Name</th> <th>Director</th> </tr> </thead> <tbody> <!-- foreach movie, a new tr will be created --> <tr ng-repeat="movie in movies"> <!-- Similar to a foreach loop, C#: foreach(var movie in movies ){...} --> <td> {{movie.Id}} </td> <td> {{movie.Name}} </td> <td> {{movie.Director}} </td> </tr> </tbody> </table> </div>
我们刚刚做了什么?
我们将硬编码的电影数据从视图移到了控制器,并添加了一个 Angular 循环函数来遍历数组并显示数据。
WebAPI 来了!
由于 Angular 在客户端运行,它无法从数据库获取数据。 这就是 WebAPI 发挥作用的地方。 所以下一步就是从 WebAPI(数据库)获取 JavaScript 对象。
创建 WebAPI 项目
- 右键单击解决方案
- Add
- 新建项目
- 选择 WebAPI
- 更改身份验证 => 无身份验证
- 命名为“CodeProjectAngular.WebAPI”
配置 WebAPI 以返回 JSON
转到 App_Start/WebApiConfig.cs 并添加以下代码
config.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html"));
上面的代码不会返回严格的“application/json”响应,如果您想要严格的“application/json”响应,可以使用下面的代码。
var json = config.Formatters.JsonFormatter; json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.None; config.Formatters.Remove(config.Formatters.XmlFormatter); json.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
创建返回类型对象
创建一个名为 DTO(数据传输对象)的文件夹,并创建一个名为“MoviesDTO”的新类,将以下代码放在 /DTO/MoviesDTO.cs 中
public class MoviesDTO { public int Id { get; set; } public string Name { get; set; } public string Director { get; set; } }
您会注意到 MoviesDTO 与我们之前硬编码的 JavaScript 对象具有相同的结构。 因此,MoviesDTO 具有 Id、Name 和 Director 属性。 当我们返回此对象时,它将自动序列化为 JSON。 接下来我们将编写返回此对象的控制器。
添加 WebAPI 控制器
- 右键单击 Controller 文件夹
- 添加 => Controller
- 选择 Web API 2 Controller – Empty
- 命名为 MoviesController
现在将以下代码粘贴到 /Controllers/MoviesController.cs 中
public IEnumerable<MoviesDTO> Get() { // this list should be fetched from the DB // you can use Entity Framework (EF) // for best practice, do not use EF inside the controller. // Instead use EF inside a class that implements an interface List<MoviesDTO> movies = new List<MoviesDTO> { new MoviesDTO { Id = 1, Name = "Fight Club", Director = "David Fincher" }, new MoviesDTO { Id = 2, Name = "Into The Wild", Director = "Sean Penn" }, new MoviesDTO { Id = 3, Name = "Dancer in the Dark", Director = "Lars von Trier" }, new MoviesDTO { Id = 4, Name = "WebAPI", Director = "Cool!" } }; return movies; }
将 WebAPI 添加到 IIS
按 Windows 键并搜索“IIS”,即 Internet Information Service。如果您没有它,可能需要安装它。
- 展开“站点”
- 右键单击“Default Web Site” => 然后选择“添加应用程序”
- 在“别名”中,输入“angular-webapi”
- 将物理路径指向您的 WebAPI 目录。
X:\ CodeProjectAngular\CodeProjectAngular.WebAPI
测试您的 WebAPI
打开您喜欢的浏览器并输入以下 URL
https:///angular-webapi/api/movies
整合一切!
现在我们只需从 Angular 调用此 WebAPI。 请注意,我们已将“$http”注入到控制器中,并将使用它来调用 WebAPI。
/App/controllers.js
angular.module('app.controllers', []) .controller('MoviesController', function ($scope, $http) { $http({ method: 'GET', url: 'https:///angular-webapi/api/movies' }) .success(function (data) { $scope.movies = data; }); });
大功告成!我们完成了!