65.9K
CodeProject 正在变化。 阅读更多。
Home

AngularJS 和 WebAPI 入门

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.83/5 (20投票s)

2015 年 2 月 9 日

CPOL

6分钟阅读

viewsIcon

71535

downloadIcon

28

本文介绍了 AngularJS 的基本架构以及如何将其连接到 WebAPI。

必备组件

  • Javascript
  • C#
  • MVC
  • Visual Studio 2013 (已安装)

 

什么是 AngularJS? (维基)

AngularJS,通常简称为 Angular,是一个由 Google 以及个人开发者和公司社区维护的开源 Web 应用程序框架,旨在解决开发单页应用程序时遇到的许多挑战。其目标是通过提供客户端模型-视图-控制器 (MVC) 架构的框架来简化此类应用程序的开发和测试。


Angular 是您项目的合适工具吗?

  1. 您是否有很多前端数据操作?
  2. 每页的记录数是否少于 2000 条?
  3. 您想构建一个单页应用程序吗?

如果您的答案是肯定的,那么我鼓励您使用 Angular。   MVC 架构可帮助您编写清晰、可维护且可重用的代码。  当记录数超过 2000 条时,Angular 运行会变慢,因此不建议使用它。

Angular 在哪里运行?

由于 Angular 是一个 JavaScript 框架,因此它在客户端运行。  我再说一遍,它在客户端运行, 在服务器上运行。

 

WebAPI 呢?

到目前为止发生了什么。

  1. 客户端请求您的网站
  2. 客户端获取相关的 HTML、CSS、JavaScript (包括 Angular)
  3. 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. 如前所述,用户访问您的网站 (1)
  2. 您的服务器响应相关的 HTML、CSS 和 JavaScript (2)
  3. Angular 开始在客户端运行


蓝色箭头代表第二阶段

  1. Angular 意识到它需要数据库中的数据,因此它要求 WebAPI 提供这些数据 (3)
  2. WebAPI 访问数据库并请求数据 (4)
  3. 数据库返回数据 (5)
  4. WebAPI 将数据重新格式化为 JSON 并将其发送给 Angular (6)

 

动手实践 Angular!

在 Visual Studio 2013 中,点击

  1. 点击“文件”
  2. 新建 => “项目”
  3. 选择“Web” => “ASP.NET Web 应用程序” => “确定”
  4. 选择“Empty” => “更改身份验证”并移除身份验证
  5. 点击“确定”

现在,创建所有文件和目录以拥有如下的项目结构。
下载以下库 jQueryAngularUi-RouterBootstrap(非必需)并将它们添加到项目中,如下图所示。

 

 

请注意,我们有一个名为 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。如果您没有它,可能需要安装它。

  1. 展开“站点”
  2. 右键单击“Default Web Site” => 然后选择“添加应用程序”
  3. 在“别名”中,输入“angular”
  4. 将物理路径指向您的项目(而不是解决方案)目录。
    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 项目

  1. 右键单击解决方案
  2. Add
  3. 新建项目
  4. 选择 WebAPI
  5. 更改身份验证 => 无身份验证
  6. 命名为“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 控制器

  1. 右键单击 Controller 文件夹
  2. 添加 => Controller
  3. 选择 Web API 2 Controller – Empty
  4. 命名为 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。如果您没有它,可能需要安装它。

  1. 展开“站点”
  2. 右键单击“Default Web Site” => 然后选择“添加应用程序”
  3. 在“别名”中,输入“angular-webapi”
  4. 将物理路径指向您的 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;
         });       

    });

 

大功告成!我们完成了!

 

© . All rights reserved.