Self-Host ASP.NET Web API 1 (C#)

作者:Mike Wasson

本教程介绍如何在控制台应用程序中托管 Web API。 ASP.NET Web API不需要 IIS。 可以在自己的主机进程中自托管 Web API。

新应用程序应使用 OWIN 自承载 Web API。 请参阅使用 OWIN Self-Host ASP.NET Web API 2

本教程中使用的软件版本

  • Web API 1
  • Visual Studio 2012

创建控制台应用程序项目

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

在“ 模板 ”窗格中,选择“ 已安装的模板 ”,然后展开 “Visual C# ”节点。 在 “Visual C#”下,选择“ Windows”。 在项目模板列表中,选择“ 控制台应用程序”。 将项目命名为“SelfHost”,然后单击“ 确定”。

“新建项目”对话框的屏幕截图,其中显示了文件夹列表中的 Visual C# 项和以灰色突出显示的“Windows 窗体应用程序”项。

(Visual Studio 2010) 设置目标框架

如果使用 Visual Studio 2010,请将目标框架更改为 .NET Framework 4.0。 (默认情况下,项目模板以 .Net Framework 客户端配置文件为目标)

在“解决方案资源管理器”中,右键单击项目并选择“属性”。 在“目标框架”下拉列表中,将目标框架更改为 .NET Framework 4.0。 当系统提示应用更改时,单击“ ”。

解决方案资源管理器窗口的屏幕截图,其中显示了“目标框架”下拉列表,其中“NET Framework 4”项以蓝色突出显示。

安装 NuGet 包管理器

NuGet 包管理器是将 Web API 程序集添加到 non-ASP.NET 项目的最简单方法。

若要检查是否安装了 NuGet 包管理器,请单击 Visual Studio 中的“工具”菜单。 如果看到名为 NuGet 包管理器的菜单项,则表示具有 NuGet 包管理器。

安装 NuGet 包管理器:

  1. 启动 Visual Studio。
  2. 在“工具”菜单上,选择“扩展和更新”
  3. “扩展和汇报”对话框中,选择“联机”。
  4. 如果未看到“NuGet 包管理器”,请在搜索框中键入“nuget 包管理器”。
  5. 选择 NuGet 包管理器,然后单击“ 下载”。
  6. 下载完成后,系统会提示安装。
  7. 安装完成后,系统可能会提示重启 Visual Studio。

“扩展和汇报”对话框的屏幕截图,其中显示了搜索结果中的 NuGet 包管理器,该管理器以灰色突出显示。

添加 Web API NuGet 包

安装 NuGet 包管理器后,将 Web API Self-Host包添加到项目中。

  1. 从“ 工具 ”菜单中,选择“ NuGet 包管理器”。 注意:如果未看到此菜单项,请确保正确安装 NuGet 包管理器。
  2. 选择“管理解决方案的 NuGet 包
  3. “管理 NugGet 包 ”对话框中,选择“ 联机”。
  4. 在搜索框中,键入“Microsoft.AspNet.WebApi.SelfHost”。
  5. 选择 ASP.NET Web API自主机包,然后单击“安装”。
  6. 安装包后,单击“ 关闭 ”关闭对话框。

注意

请确保安装名为 Microsoft.AspNet.WebApi.SelfHost 的包,而不是 AspNetWebApi.SelfHost。

“管理 NuGet 包”对话框的屏幕截图,其中显示了以蓝色突出显示的 Microsoft A S P 点 Net Web A P I 自主机。

创建模型和控制器

本教程使用与入门教程相同的模型和控制器类。

添加名为 Product的公共类。

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

添加名为 ProductsController的公共类。 从 System.Web.Http.ApiController 派生此类。

namespace SelfHost
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Net;
    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));
        }
    }
}

有关此控制器中的代码的详细信息,请参阅入门教程。 此控制器定义三个 GET 操作:

URI 说明
/api/products 获取所有产品的列表。
/api/products/id 按 ID 获取产品。
/api/products/?category=category 按类别获取产品列表。

托管 Web API

打开文件 Program.cs 并添加以下 using 语句:

using System.Web.Http;
using System.Web.Http.SelfHost;

将以下代码添加到 Program 类。

var config = new HttpSelfHostConfiguration("http://localhost:8080");

config.Routes.MapHttpRoute(
    "API Default", "api/{controller}/{id}", 
    new { id = RouteParameter.Optional });

using (HttpSelfHostServer server = new HttpSelfHostServer(config))
{
    server.OpenAsync().Wait();
    Console.WriteLine("Press Enter to quit.");
    Console.ReadLine();
}

(可选) 添加 HTTP URL 命名空间预留

此应用程序侦 http://localhost:8080/听 。 默认情况下,侦听特定 HTTP 地址需要管理员权限。 因此,运行本教程时,可能会收到此错误:“HTTP 无法注册 URL http://+:8080/"有两种方法可以避免此错误:

  • 使用提升的管理员权限运行 Visual Studio,或者
  • 使用 Netsh.exe 为帐户授予保留 URL 的权限。

若要使用Netsh.exe,请使用管理员权限打开命令提示符,然后输入以下命令:以下命令:

netsh http add urlacl url=http://+:8080/ user=machine\username

其中 machine\username 是你的用户帐户。

完成自承载后,请务必删除预留:

netsh http delete urlacl url=http://+:8080/

从客户端应用程序调用 Web API (C#)

让我们编写一个调用 Web API 的简单控制台应用程序。

向解决方案添加新的控制台应用程序项目:

  • 在“解决方案资源管理器”中,右键单击解决方案,然后选择“添加新项目”。
  • 创建名为“ClientApp”的新控制台应用程序。

解决方案资源管理器的屏幕截图,其中显示了右键单击菜单项“添加”和“新建项目”,以白色突出显示。

使用 NuGet 包管理器添加 ASP.NET Web API核心库包:

  • 从“工具”菜单中,选择“ NuGet 包管理器”。
  • 选择“管理解决方案的 NuGet 包
  • “管理 NuGet 包 ”对话框中,选择“ 联机”。
  • 在搜索框中,键入“Microsoft.AspNet.WebApi.Client”。
  • 选择“Microsoft ASP.NET Web API客户端库”包,然后单击“安装”。

在 ClientApp 中向 SelfHost 项目添加引用:

  • 在“解决方案资源管理器”中,右键单击“ClientApp”项目。
  • 选择“添加引用”。
  • “引用管理器 ”对话框的“ 解决方案”下,选择“ 项目”。
  • 选择 SelfHost 项目。
  • 单击" 确定"。

“引用管理器”对话框的屏幕截图,其中显示了“自承载”项目,该项目用蓝色框突出显示。

打开 Client/Program.cs 文件。 添加以下 using 语句:

using System.Net.Http;

添加静态 HttpClient 实例:

namespace Client
{
    class Program
    {
        static HttpClient client = new HttpClient();
    }
}

添加以下方法以列出所有产品、按 ID 列出产品以及按类别列出产品。

static void ListAllProducts()
{
    HttpResponseMessage resp = client.GetAsync("api/products").Result;
    resp.EnsureSuccessStatusCode();

    var products = resp.Content.ReadAsAsync<IEnumerable<SelfHost.Product>>().Result;
    foreach (var p in products)
    {
        Console.WriteLine("{0} {1} {2} ({3})", p.Id, p.Name, p.Price, p.Category);
    }
}

static void ListProduct(int id)
{
    var resp = client.GetAsync(string.Format("api/products/{0}", id)).Result;
    resp.EnsureSuccessStatusCode();

    var product = resp.Content.ReadAsAsync<SelfHost.Product>().Result;
    Console.WriteLine("ID {0}: {1}", id, product.Name);
}

static void ListProducts(string category)
{
    Console.WriteLine("Products in '{0}':", category);

    string query = string.Format("api/products?category={0}", category);

    var resp = client.GetAsync(query).Result;
    resp.EnsureSuccessStatusCode();

    var products = resp.Content.ReadAsAsync<IEnumerable<SelfHost.Product>>().Result;
    foreach (var product in products)
    {
        Console.WriteLine(product.Name);
    }
}

其中每种方法都遵循相同的模式:

  1. 调用 HttpClient.GetAsync 将 GET 请求发送到相应的 URI。
  2. 调用 HttpResponseMessage.EnsureSuccessStatusCode。 如果 HTTP 响应状态为错误代码,此方法将引发异常。
  3. 调用 ReadAsAsync<T> 以从 HTTP 响应反序列化 CLR 类型。 此方法是在 System.Net.Http.HttpContentExtensions 中定义的扩展方法。

GetAsyncReadAsAsync 方法都是异步的。 它们返回表示异步操作的 Task 对象。 获取 Result 属性会阻止线程,直到操作完成。

有关使用 HttpClient 的详细信息,包括如何进行非阻止调用,请参阅 从 .NET 客户端调用 Web API

在调用这些方法之前,请将 HttpClient 实例上的 BaseAddress 属性设置为“http://localhost:8080”。 例如:

static void Main(string[] args)
{
    client.BaseAddress = new Uri("http://localhost:8080");

    ListAllProducts();
    ListProduct(1);
    ListProducts("toys");

    Console.WriteLine("Press Enter to quit.");
    Console.ReadLine();
}

这应输出以下内容。 (请记得先运行 SelfHost 应用程序。)

1 Tomato Soup 1.0 (Groceries)
2 Yo-yo 3.75 (Toys)
3 Hammer 16.99 (Hardware)
ID 1: Tomato Soup
Products in 'toys':
Yo-yo
Press Enter to quit.

控制台窗口的屏幕截图,其中显示了与 ID 和类别关联的产品的输出列表。