在 Azure 辅助角色中托管 ASP.NET Web API 2

作者:Mike Wasson

本教程介绍如何使用 OWIN 在 Azure 辅助角色中托管 ASP.NET Web API,以自承载 Web API 框架。

.NET (OWIN) .NET 开放 Web 接口定义 .NET Web 服务器和 Web 应用程序之间的抽象。 OWIN 将 Web 应用程序与服务器分离,这使得 OWIN 非常适合在自己的进程(IIS 外部)(例如,在 Azure 辅助角色内部)中自托管 Web 应用程序。

在本教程中,你将使用 Microsoft.Owin.Host.HttpListener 包,该包提供用于自承载 OWIN 应用程序的 HTTP 服务器。

本教程中使用的软件版本

创建 Microsoft Azure 项目

使用管理员权限启动 Visual Studio。 使用 Azure 计算模拟器在本地调试应用程序需要管理员权限。

在“ 文件 ”菜单上,单击“ 新建”,然后单击“ 项目”。 在 “已安装的模板”中,在“Visual C#”下,单击“ ”,然后单击“ Windows Azure 云服务”。 将项目命名为“AzureApp”,然后单击“ 确定”。

“新建项目”对话框的屏幕截图,其中突出显示了菜单选项中用于创建Azure 应用项目的步骤。

“新建 Windows Azure 云服务 ”对话框中,双击“ 辅助角色”。 保留默认名称 (“WorkerRole1”) 。 此步骤将辅助角色添加到解决方案。 单击" 确定"。

“新建 Windows Azure 云服务”对话框的屏幕截图,其中显示了用于创建辅助角色的菜单选项。

创建的 Visual Studio 解决方案包含两个项目:

  • “AzureApp”定义 Azure 应用程序的角色和配置。
  • “WorkerRole1”包含辅助角色的代码。

通常,尽管本教程使用单个角色,但 Azure 应用程序可以包含多个角色。

解决方案资源管理器窗口的屏幕截图,其中突出显示了新的Azure 应用项目,并在其下方显示了应用名称和辅助角色选项。

添加 Web API 和 OWIN 包

“工具 ”菜单中,单击“ NuGet 包管理器”,然后单击“ 包管理器控制台”。

在“Package Manager Console”窗口中,输入以下命令:

Install-Package Microsoft.AspNet.WebApi.OwinSelfHost

添加 HTTP 终结点

在“解决方案资源管理器”中,展开“AzureApp”项目。 展开“角色”节点,右键单击“WorkerRole1”,然后选择“ 属性”。

解决方案资源管理器窗口菜单的屏幕截图,其中突出显示了选择辅助角色的属性设置的步骤。

单击“终结点”,然后单击“添加终结点”

“协议 ”下拉列表中,选择“http”。 在 “公共端口 ”和 “专用端口”中,键入“80”。 这些端口号可以不同。 公共端口是客户端向角色发送请求时使用的内容。

协议下拉菜单选项的屏幕截图,其中显示了不同的服务配置和终结点选项。

为 Self-Host 配置 Web API

在“解决方案资源管理器”中,右键单击“WorkerRole1”项目,然后选择“添加 / ”以添加新类。 命名类 Startup

解决方案资源管理器窗口的屏幕截图,其中显示了菜单选项并突出显示了添加类的路径。

将此文件中的所有样本代码替换为以下内容:

using Owin;
using System.Web.Http;

namespace WorkerRole1
{
    class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            HttpConfiguration config = new HttpConfiguration();
            config.Routes.MapHttpRoute(
                "Default",
                "{controller}/{id}",
                new { id = RouteParameter.Optional });

            app.UseWebApi(config);
        }
    }
}

添加 Web API 控制器

接下来,添加 Web API 控制器类。 右键单击 WorkerRole1 项目,然后选择“ 添加 / ”。 将类命名为 TestController。 将此文件中的所有样本代码替换为以下内容:

using System;
using System.Net.Http;
using System.Web.Http;

namespace WorkerRole1
{
    public class TestController : ApiController
    {
        public HttpResponseMessage Get()
        {
            return new HttpResponseMessage()
            {
                Content = new StringContent("Hello from OWIN!")
            };
        }

        public HttpResponseMessage Get(int id)
        {
            string msg = String.Format("Hello from OWIN (id = {0})", id);
            return new HttpResponseMessage()
            {
                Content = new StringContent(msg)
            };
        }
    }
}

为简单起见,此控制器只定义返回纯文本的两个 GET 方法。

启动 OWIN 主机

打开 WorkerRole.cs 文件。 此类定义启动和停止辅助角色时运行的代码。

添加以下 using 语句:

using Microsoft.Owin.Hosting;

IDisposable 成员添加到 WorkerRole 类:

public class WorkerRole : RoleEntryPoint
{
    private IDisposable _app = null;

    // ....
}

OnStart在 方法中,添加以下代码以启动主机:

public override bool OnStart()
{
    ServicePointManager.DefaultConnectionLimit = 12;

    // New code:
    var endpoint = RoleEnvironment.CurrentRoleInstance.InstanceEndpoints["Endpoint1"];
    string baseUri = String.Format("{0}://{1}", 
        endpoint.Protocol, endpoint.IPEndpoint);

    Trace.TraceInformation(String.Format("Starting OWIN at {0}", baseUri), 
        "Information");

    _app = WebApp.Start<Startup>(new StartOptions(url: baseUri));
    return base.OnStart();
}

WebApp.Start 方法启动 OWIN 主机。 类的名称 Startup 是 方法的类型参数。 按照约定,主机将调用 Configure 此类的 方法。

OnStop重写 以释放_app实例:

public override void OnStop()
{
    if (_app != null)
    {
        _app.Dispose();
    }
    base.OnStop();
}

下面是 WorkerRole.cs 的完整代码:

using Microsoft.Owin.Hosting;
using Microsoft.WindowsAzure.ServiceRuntime;
using System;
using System.Diagnostics;
using System.Net;
using System.Threading;

namespace WorkerRole1
{
    public class WorkerRole : RoleEntryPoint
    {
        private IDisposable _app = null;

        public override void Run()
        {
            Trace.TraceInformation("WebApiRole entry point called", "Information");

            while (true)
            {
                Thread.Sleep(10000);
                Trace.TraceInformation("Working", "Information");
            }
        }

        public override bool OnStart()
        {
            ServicePointManager.DefaultConnectionLimit = 12;

            var endpoint = RoleEnvironment.CurrentRoleInstance.InstanceEndpoints["Endpoint1"];
            string baseUri = String.Format("{0}://{1}", 
                endpoint.Protocol, endpoint.IPEndpoint);

            Trace.TraceInformation(String.Format("Starting OWIN at {0}", baseUri), 
                "Information");

            _app = WebApp.Start<Startup>(new StartOptions(url: baseUri));
           return base.OnStart();
        }

        public override void OnStop()
        {
            if (_app != null)
            {
                _app.Dispose();
            }
            base.OnStop();
        }
    }
}

生成解决方案,然后按 F5 在 Azure 计算模拟器中本地运行应用程序。 根据防火墙设置,可能需要允许模拟器通过防火墙。

注意

如果遇到如下所示的异常,请参阅 此博客文章 了解解决方法。 “无法加载文件或程序集 'Microsoft.Owin, Version=2.0.2.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' 或其依赖项之一。 找到的程序集清单定义与程序集引用不匹配。 (HRESULT 的异常:0x80131040) ”

计算模拟器将本地 IP 地址分配给终结点。 可以通过查看计算模拟器 UI 来查找 IP 地址。 右键单击任务栏通知区域中的模拟器图标,然后选择“ 显示计算模拟器 UI”。

Azure 计算模拟器 UI 的屏幕截图,其中显示了选择“服务详细信息”选项时的菜单和 IP 终结点地址信息。

在“服务部署”、“部署 [id]”、“服务详细信息”下查找 IP 地址。 打开 Web 浏览器并导航到 http:// address/test/1,其中 address 是计算模拟器分配的 IP 地址;例如 , http://127.0.0.1:80/test/1。 应会看到来自 Web API 控制器的响应:

浏览器窗口的屏幕截图,其中显示了输入计算模拟器分配的 I P 地址后 Web API 控制器响应。

部署到 Azure

对于此步骤,必须有一个 Azure 帐户。 如果没有帐户,只需几分钟即可创建一个免费试用帐户。 有关详细信息,请参阅 Microsoft Azure 免费试用版

在“解决方案资源管理器”中,右键单击“AzureApp”项目。 选择“发布”。

解决方案资源管理器窗口菜单选项的屏幕截图,其中突出显示了部署或发布项目所要遵循的步骤。

如果未登录到 Azure 帐户,请单击“ 登录”。

“发布 Azure 应用程序”对话框的屏幕截图,该对话框在其他选项可用之前请求登录选项。

登录后,选择订阅并单击“ 下一步”。

登录后“发布 Azure 应用程序”的屏幕截图,提示用户在继续下一步之前选择订阅类型。

输入云服务的名称,然后选择一个区域。 单击“创建”。

“创建云服务和存储帐户”对话框的屏幕截图,请求用户输入其应用程序服务的名称和区域。

单击“发布” 。

“发布 Azure 应用程序”窗口的屏幕截图,其中确认了所做的所有设置选择,并提供返回或发布的按钮选项。

为 Azure 云服务(经典)配置自定义域名

其他资源