• 初尝Web API《转》


    HTTP 并不是只能用在网页中。它其实还是一个强大的平台,可以用来生成一些API,暴露服务和数据。HTTP很简单灵活,还非常普及。几乎所有你能想到的平台都有HTTP库,所以HTTP服务可以囊括很大范围的客户端,包括浏览器,移动设备和传统的桌面程序。

    ASP.NET Web API 是.NET Framework上的一个框架,用来生成 web API。 本文将使用ASP.NET Web API来创建一个web API,返回一组商品。前端页面用jQuery来显示结果。

    点此下载完整工程。

    首先需要安装了ASP.NET MVC 4的 Visual Studio 。下面的用哪个都行:

    • Visual Studio 2012
    • Visual Studio Express 2012 for Web
    • Visual Studio 2010 且已安装 ASP.NET MVC 4 。
    • Visual Web Developer 2010 Express 且已安装 ASP.NET MVC 4 。

    如果用的是 Visual Studio 2010 或者 Visual Web Developer 2010 Express ,需要另外安装 ASP.NET MVC 4 。本文的截图都是用的 Visual Studio Express 2012 for Web。

    创建 Web API 工程

    启动 Visual Studio ,在开始页里选择“新建项目”。或者从“文件”菜单里,选择“新建项目”。

    在模板面板中,选择“已安装”,并展开 Visual C# 节点。在 Visual C# 下面,选择 Web。在项目模板列表中,选择 ASP.NET MVC 4 Web 应用程序。将项目命名为 "HelloWebAPI" 然后点击“确定”。

    在弹出的“新 ASP.NET MVC 4 项目”对话框中,选择“Web API”然后点“确定”。

    添加模型

    模型是指程序里的对象。 ASP.NET Web API 能够自动序列化模型为JSON,XML或者其它的格式,然后将序列化后的数据写入HTTP响应信息体里。只要客户端能读到序列化格式,它就能反序列化为对象。大部分的客户端都能够解析XML或JSON。 而且,客户端通过设置HTTP请求信息里的Accept头就能够表明它想要什么样的格式。

    我们就创建一个表示商品的模型来开始吧。

    如果解决方案资源管理器没显示的话,点击“视图”菜单并选择“解决方案资源管理器”。在解决方案资源管理器重,右击“Models”文件夹。在弹出菜单中,选择“添加“,”类“。

    将类命名为 "Product"。接下来在 Product 类里加入下面的属性:

    namespace HelloWebAPI.Models
    {
        public class Product
        {
            public int Id { get; set; }
            public string Name { get; set; }
            public string Category { get; set; }
            public decimal Price { get; set; }
        }
    }

    添加控制器

    控制器是一个处理HTTP请求的对象。当你创建完项目以后,”新建项目“向导就自动创建了2个控制器。在解决方案资源管理器里展开”Controllers“目录就能看到了。

    • HomeController 是一个传统的 ASP.NET MVC 控制器。它只是负责处理站点的HTML页,跟Web API没有直接关系。
    • ValuesController 是一个示例 WebAPI 控制器。

    注意  如果你之前已经搞过 ASP.NET MVC,那你肯定已经对控制器很熟了。它在Web API里也是类似的,只不过在Web API里控制器不是从Controller类继承而是从ApiController类继承了。你会注意到,第一个主要的不同点是Web API上的操作并不返回视图,而是返回数据。

    解决方案资源管理里右击 ValuesController, 选择”删除“直接把他删掉。

    如下所示,添加一个新的控制器:

    解决方案资源管理里,右击 Controllers 目录,选择”添加“,”控制器“:

    在”添加控制器“向导中,将控制器命名为 "ProductsController"。”模板“下拉框中,选择”空API控制器“。然后点”添加“。

    ”添加控制器“向导在Controllers目录下创建一个名为 ProductsController.cs 的控制器。

    没有必要非得把控制器放到Controllers目录里。目录名并不重要,只是为了方便我们组织代码文件,这么起名比较简单。

    如果这个文件没有打开,那就双击它打开(译注:老外真是啰嗦,像唐僧似的……偷笑)。添加如下的实现代码:

    namespace HelloWebAPI.Controllers
    {
        using HelloWebAPI.Models;
        using System;
        using System.Collections.Generic;
        using System.Linq;
        using System.Net;
        using System.Net.Http;
        using System.Web.Http;
    
        public class ProductsController : ApiController
        {
    
            Product[] products = new Product[] 
            { 
                new Product { Id = 1, Name = "Tomato Soup", Category = "Groceries", Price = 1 }, 
                new Product { Id = 2, Name = "Yo-yo", Category = "Toys", Price = 3.75M }, 
                new Product { Id = 3, Name = "Hammer", Category = "Hardware", Price = 16.99M } 
            };
    
            public IEnumerable<Product> GetAllProducts()
            {
                return products;
            }
    
            public Product GetProductById(int id)
            {
                var product = products.FirstOrDefault((p) => p.Id == id);
                if (product == null)
                {
                    throw new HttpResponseException(HttpStatusCode.NotFound);
                }
                return product;
            }
    
            public IEnumerable<Product> GetProductsByCategory(string category)
            {
                return products.Where(
                    (p) => string.Equals(p.Category, category,
                        StringComparison.OrdinalIgnoreCase));
            }
        }
    }

    为了让例子保持简单,我们直接把产品存到控制器类里的一个固定数组里。当然,在实际的程序里需要从数据库里查询或者用其它的一些外部数据源。

    控制器定义了三个方法,要么返回单个商品,要么返回一组产品:

    • GetAllProducts 方法返回所有的产品,返回类型为 IEnumerable<Product> 。
    • GetProductById 方法通过ID查询某个产品。
    • GetProductsByCategory 方法返回指定分类的所有产品。

    完事儿了!web API已经能用了。每一个控制器上的方法都对应了一个URI:

    控制器方法URI
    GetAllProducts /api/products
    GetProductById /api/products/id
    GetProductsByCategory /api/products/?category=category

    客户端只要通过放松一个HTTP GET请求到URI就可以调用相应的方法。待会儿我们来看看这个映射是怎么做的。但首先我们先把它跑起来试试。

    从浏览器调用 Web API 

    任何HTTP客户端都可以用来调用 web API。其实可以从web浏览器直接调用。

    在 Visual Studio 里,选择“调试”菜单,然后“启动调试”,或者按F5键。 ASP.NET Development Server 就会启动起来(译者注:在VS2012默认的应该是IIS Express), 在屏幕的右下角会出现一个通知图标,显示它正运行在哪个端口。默认情况下, Development Server 会选择一个随机的端口号。

    然后Visual Studio 会自动打开浏览器窗口, URL 指向 http//localhost:xxxx/, xxxx 就是端口号。首页应该看起来如下图:

    首页是一个 ASP.NET MVC 视图,由 HomeController 类返回。想要调用 web API,就得用到前边儿列出来的URI之一。比如,要获取所有商品列表,那就浏览 http://localhost:xxxx/api/products/. (将 "xxxx" 替换为真实的端口号)

    实际显示结果要看你使用什么浏览器来决定。IE会提示你打开或保存一个名为products的“文件”。

    这个“文件”其实只是HTTP响应体。点击“打开”。在“打开方式”对话框“,选择”记事本“。点击”确定“,弹出提示的时候点”打开“。文件应该包含了一个JSON,表示产品的数组。

    [{"Id":1,"Name":"Tomato soup","Category":"Groceries","Price":1.0},{"Id":2,"Name":
    "Yo-yo","Category":"Toys","Price":3.75},{"Id":3,"Name":"Hammer","Category":
    "Hardware","Price":16.99}]

    如果是Mozilla Firefox,会在浏览器里以XML形式显示列表。

    为什么会不一样呢?因为 Internet Explorer 和 Firefox 发送了不同的 Accept 头,所以 web API 在响应里就发送了不同的内容类型。

    自己浏览这俩 URI 试试:

    • http://localhost:xxxx/api/products/1
    • http://localhost:xxxx/api/products?category=hardware

    第一个应该返回ID等于1的条目。第二个应该返回Category等于”hardware“的所有产品列表(这里只有一个条目)。

    用JavaScript和jQuery调用 Web API 

    前一节里我们直接在浏览器里访问 web API 。但是大部分 web API 主要目的还是有客户端程序以编程方式来用。所以我们来写一个简单的JavaScript客户端。

    在解决方案资源管理器重,展开Views目录,然后展开它下面的Home目录。可以看到一个名为Index.cshtml的文件。双击这个文件打开。

    Index.cshtml 使用 Razor 视图引擎 渲染HTML页。 但是此处我们不使用任何Razor特性,因为我要演示客户端如何使用纯HTML和Javascript访问服务。因此,删掉这个文件里的所有东西,用下面的代码替换之:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <title>ASP.NET Web API</title>
        <link href="../../Content/Site.css" rel="stylesheet" />
        <script src="../../Scripts/jquery-1.7.1.min.js" type="text/javascript">
            // TODO Add script
        </script>
    </head>
    <body id="body" >
        <div class="main-content">
            <div>
                <h1>All Products</h1>
                <ul id="products"/>
            </div>
            <div>
                <label for="prodId">ID:</label>
                <input type="text" id="prodId" size="5"/>
                <input type="button" value="Search" onclick="find();" />
                <p id="product" />
            </div>
        </div>
    </body>
    </html>

    获取产品列表

    要获取产品列表,通过发送 HTTP GET 请求到 "/api/products"。可以像下面这样用jQuery来实现:

    <script type="text/javascript">
        $(document).ready(function () {
            // Send an AJAX request
            $.getJSON("api/products/",
            function (data) {
                // On success, 'data' contains a list of products.
                $.each(data, function (key, val) {
    
                    // Format the text to display.
                    var str = val.Name + ': $' + val.Price;
    
                    // Add a list item for the product.
                    $('<li/>', { text: str })    
                    .appendTo($('#products'));   
                });
            });
        });
    </script>

    getJSON 函数用来发送 AJAX 请求。 响应将是一个JSON对象数组。getJSON的第二个参数是一个回调函数,当请求成功完成时将调用。

    通过ID获取产品

    要根据ID获取产品,通过发送 HTTP GET  请求到 "/api/products/id",这里的id就是产品的ID。将以下代码添加到脚本块儿里:

    function find() {
        var id = $('#prodId').val();
        $.getJSON("api/products/" + id,
            function (data) {
                var str = data.Name + ': $' + data.Price;
                $('#product').text(str);
            })
        .fail(
            function (jqXHR, textStatus, err) {
                $('#product').text('Error: ' + err); 
            });
    }            

    我们再一次通过调用 jQuery 的 getJSON 函数来发送 AJAX 请求,但这次我们用ID来构造这个请求URI。这个请求的响应是一个JSON,表示单个产品对象。

    完整的 Index.cshtml 文件如下:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <title>ASP.NET Web API</title>
        <link href="../../Content/Site.css" rel="stylesheet" />
        <script src="../../Scripts/jquery-1.7.1.min.js" 
            type="text/javascript"></script>
    
            <script type="text/javascript">
                $(document).ready(function () {
                    // Send an AJAX request
                    $.getJSON("api/products/",
                    function (data) {
                        // On success, 'data' contains a list of products.
                        $.each(data, function (key, val) {
    
                            // Format the text to display.
                            var str = val.Name + ': $' + val.Price;
    
                            // Add a list item for the product.
                            $('<li/>', { text: str })
                            .appendTo($('#products'));
                        });
                    });
                });
    
                function find() {
                    var id = $('#prodId').val();
                    $.getJSON("api/products/" + id,
                        function (data) {
                            var str = data.Name + ': $' + data.Price;
                            $('#product').text(str);
                        })
                    .fail(
                        function (jqXHR, textStatus, err) {
                            $('#product').text('Error: ' + err);
                        });
                }
            </script>
    
    </head>
    <body id="body" >
        <div class="main-content">
            <div>
                <h1>All Products</h1>
                <ul id="products"/>
            </div>
            <div>
                <label for="prodId">ID:</label>
                <input type="text" id="prodId" size="5"/>
                <input type="button" value="Search" onclick="find();" />
                <p id="product" />
            </div>
        </div>
    </body>
    </html>

    运行程序

    按下 F5 启动调试程序。网页应该如下图所示:

    这不是最好的web设计,但它演示了HTTP服务是可行的。通过在文本框内输入ID就可以通过这个ID获取产品。

    如果输入了无效ID,服务器将返回一个HTTP错误:

    理解路由

    本节解释ASP.NET Web API是如何将URI映射到控制器方法的。详见 Routing in ASP.NET Web API.

    对于每一个HTTP消息, ASP.NET Web API 框架通过询问路由表来决定由哪个控制器接收。当新建一个Web API项目时,项目就包含了一个默认的路由,如下所示:

    /api/{controller}/{id}

    {controller} 和 {id} 是占位符。当框架看到匹配此模式的URI时,它会去找相应的方法来调用,匹配规则如下:

    • {controller} 与控制器名称匹配。
    • HTTP 请求方法与方法名匹配。 (此规则只对 GET, POST, PUT, 和 DELETE 请求使用.)
    • {id}, 如果有,与名为id的方法参数匹配。
    • 可能的话,查询参数与参数名称匹配。

    基于我们当前的实现,这里是一些示例请求,以及各自的操作。

    URIHTTP 方法操作
    /api/products GET GetAllProducts()
    /api/products/1 GET GetProductById(1)
    /api/products?category=hardware GET GetProductsByCategory("hardware")

    在第一个例子中, "products" 与名为 ProductsController 的控制器匹配。由于是一个 GET 请求,所以框架在ProductsController 上去找名字以"Get..."开头的方法。此外,URI不包含可选的 {id} 段,所以框架去找没有参数的方法。ProductsController::GetAllProducts 方法满足所有这些要求。

    第二个例子是一样的,除了URI包含了 {id} 部分。因此,框架调用 GetProduct,它有一个名为id的参数。还有,注意URI中值“5”作为id参数传入。框架会基于方法签名,自动将“5"转换为int类型。

    这里是一些会导致路由错误的请求:

    URIHTTP 方法操作
    /api/products/ POST 405 Method Not Allowed
    /api/users/ GET 404 Not Found
    /api/products/abc GET 400 Bad Request

    第一个例子,客户端发送了一个 HTTP POST 请求。框架去找名字以”Post...“开头的方法。但是在ProductsController里根本不存在这样的方法,所以框架返回一个 HTTP 响应,状态405,Method Not Allowed。

    对于 /api/users 的请求失败,因为压根就没有名为 UsersController 的控制器。对 api/products/abc 的请求失败,因为id参数是int类型,而 URI 段的"abc" 无法转换为int。

    使用 F12 查看 HTTP 请求和响应

    当使用 HTTP 服务时,查看HTTP请求和请求消息非常有用。在IE9里通过F12开发者工具就能做到。IE9里,按下F12,打开工具。点击”网络“页签,按下”开始捕获“按钮。回到网页并按F5重新加载网页。IE就会捕获浏览器和服务器间的HTTP流量。”摘要视图“显示一个页面的所有网络流量。

    找到相对URI “api/products/” 的条目。选择此条目点击”转到详细视图“。在详细视图里,可以看到请求和响应的标头和正文。比如,如果点击”请求标头“页签,就可以看到客户端在Accept标头里请求了"application/json"。

    如果点击”响应正文“标签,可以看到产品列表时如何序列化为JSON的。其它的浏览器也有类似的功能。另一个有用的工具是 Fiddler,一个web 调试代理。你可以用Fiddler来查看HTTP流量,还可以组合HTTP请求,这样你可以对请求中的HTTP标头进行完全控制。

    下一步

    想查看完整的支持POST, PUT, 和DELETE操作的HTTP服务例子,见:

    Web API 不要求一定用 ASP.NET MVC. 其它的选择见:

    原文地址:http://www.asp.net/web-api/overview/getting-started-with-aspnet-web-api/tutorial-your-first-web-api

  • 相关阅读:
    [SSRS] Use Enum values in filter expressions Dynamics 365 Finance and Operation
    Power shell deploy all SSRS report d365 FO
    display method in Dynamics 365 FO
    How To Debug Dynamics 365 Finance and Operation
    Computed columns and virtual fields in data entities Dynamics 365
    Azure DevOps for Power Platform Build Pipeline
    Create readonly entities that expose financial dimensions Dynamics 365
    Dataentity call stack dynamics 365
    Dynamics 365 FO extension
    Use singletenant servertoserver authentication PowerApps
  • 原文地址:https://www.cnblogs.com/tomahawk/p/4063031.html
Copyright © 2020-2023  润新知