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

关于 Owin 托管服务的说明

starIconstarIconstarIconstarIconstarIcon

5.00/5 (8投票s)

2017 年 6 月 18 日

CPOL

11分钟阅读

viewsIcon

23203

downloadIcon

176

这是一篇关于 Owin (Open Web Interface for .NET) 托管服务的说明。

引言

这是一篇关于 Owin (Open Web Interface for .NET) 托管服务的说明。

背景

这是一篇关于 Owin 托管服务的说明。本文档并非旨在成为 Owin 的完整参考。它仅讨论了在使用 Owin 提供 Web 内容时遇到的一些有趣问题。

附件是一个在 Visual Studio 2015 中创建的解决方案。它包含六个小型控制台应用程序,每个应用程序都涵盖了使用 Owin 时的一个主题。如果您想运行这些应用程序,建议以管理员身份启动 Visual Studio。否则,您可能无法在调试模式下启动服务。

A-Minimal-Owin-Application (一个最小的 Owin 应用程序)

作为第一步,创建一个最小的 Owin 应用程序会很有帮助。

要创建一个最小的 Owin 应用程序,您需要安装至少三个 Nuget 包。这三个包依赖的任何 Nuget 包都将由 Visual Studio 自动安装到项目中。

由于目的是保持应用程序的最小化,所有用于启动 Owin 服务的代码都在“Program.cs”文件中。

using Microsoft.Owin.Hosting;
using Owin;
using System;
using System.Web.Http;
    
namespace A_Minimal_Owin_Application
{
    /// <summary>
    /// To start an Owin service, the minimal Nuget packages needed are
    /// 1. Microsoft.Owin.Hosting
    /// 2. Microsoft.Owin.Host.HttpListener
    /// 3. Microsoft.AspNet.WebApi.Owin
    /// 4. The rest of the packges are the dependencies of the 3 above
    /// </summary>
    class Program
    {
        static void Main(string[] args)
        {
            WebApp.Start<Startup>("http://*:800/");
            WebApp.Start<Startup>("http://*:900/");
    
            Console.WriteLine("A_Minimal_Owin_Application started");
            Console.Write("Type any key to stop ... ");
            Console.Read();
        }
    }
    
    class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            // Configure the web apis
            HttpConfiguration config = new HttpConfiguration();
    
            config.MapHttpAttributeRoutes();
            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "{controller}/{action}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );
    
            app.UseWebApi(config);
        }
    }
    
    public class ResponsePayload
    {
        public string Text { get; set; }
    }
    
    public class AConcreteController : ApiController
    {
        private int i = 0;
    
        public ResponsePayload getAString()
        {
            i++;
            return new ResponsePayload() {
                Text = "i = " + i
            };
        }
    }

    [RoutePrefix("A")]
    public class AnotherConcreteController : ApiController
    {
        [HttpGet]
        [Route("B")]
        public ResponsePayload getAString(string A)
        {
            return new ResponsePayload() {
                Text = A
            };
        }
    }
}

“Startup”类

要启动 Owin 服务,我们需要一个 Owin 启动类。

  • “Startup”类会告知 Owin 如何处理 Web 请求。类名并不重要,但它需要实现“public void Configuration(IAppBuilder app)”方法。
  • 当程序运行时,我们可以使用“WebApp.Start<Startup>("http://*:800/")”语法来启动 Owin 应用程序。我们可以多次调用“WebApp.Start()”让 Owin 应用程序监听多个端口号。

控制器类

当 Web 请求到达 Owin 服务时,Owin 会响应该 Web 请求。通常,响应是在控制器类中实现的。

  • 所有控制器类都需要是“ApiController”类的子类。
  • 所有控制器类都需要是公共类。
  • 所有控制器类都需要实现一些动作方法。所有动作方法都需要是公共方法。
  • 默认情况下,GET 请求“https://:800/AConcrete/getAString”被映射到“AConcreteController”类中的“getAString()”方法。
  • 我们可以使用“RoutePrefix()”、“Route()”和“HttpGet”注解来更改请求映射。GET 请求“https://:800/A/B?A=ABCD”被映射到“AnotherConcreteController”类中的“getAString()”方法。

运行应用程序

当 Owin 应用程序启动时,Owin 会搜索任何可用程序集中的“ApiController”类的公共子类。当 HTTP 请求到来时,如果映射规则确定了其中一个控制器类中的公共动作方法,Owin 将创建一个控制器类的实例并通过该动作方法处理请求。由于我们配置 Owin 监听端口 800 和 900,我们可以使用其中任何一个端口号来访问服务。

  • 如果我们通过 POSTMAN 向“https://:800/AConcrete/getAString”发出 GET 请求,将调用“AConcreteController”类中的“getAString()”方法,响应为“{"Text": "i = 1"}”。如果我们再次发出相同的请求,将返回相同的响应。如果您想在控制器类中使用任何实例变量,您需要意识到 Owin 会为每个请求创建一个控制器类的新实例。
  • 如果我们向“https://:800/A/B?A=ABCD”发出 GET 请求,Owin 将使用“AnotherConcreteController”类中的“getAString()”方法来响应请求。

以下是 POSTMAN 接收到的对请求“https://:800/A/B?A=ABCD”的响应。

B-Middle-Ware (中间件)

如果您使用过“Node.JS”,您应该熟悉中间件。中间件是一个拦截所有 Web 请求的函数。我们可以使用中间件来修改默认响应行为。

有许多方法可以将中间件添加到 Owin。在本说明中,我使用了最简单的方法(至少在语法上)在“Startup”类中的“Configuration()”方法中添加中间件。

using Microsoft.Owin.Hosting;
using Owin;
using System;
using System.Web.Http;
    
namespace B_Middle_Ware
{
    class Program
    {
        static void Main(string[] args)
        {
            WebApp.Start<Startup>("http://*:800/");
    
            Console.WriteLine("B_Middle_Ware started");
            Console.Write("Type any key to stop ... ");
            Console.Read();
        }
    }
    
    class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            // A middleware Disable browser cache for all the request
            app.Use((ctx, next) =>
            {
                ctx.Response.Headers["Cache-Control"]
                    = "no-cache, no-store, must-revalidate";
                ctx.Response.Headers["Pragma"] = "no-cache";
                ctx.Response.Headers["Expires"] = "-1";
    
                return next();
            });
    
            // Configure the web apis
            HttpConfiguration config = new HttpConfiguration();
    
            config.MapHttpAttributeRoutes();
            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "{controller}/{action}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );
    
            app.UseWebApi(config);
        }
    }
    
    public class ResponsePayload
    {
        public string Text { get; set; }
    }
    
    public class AConcreteController : ApiController
    {
        [HttpGet]
        public ResponsePayload getAString()
        {
            return new ResponsePayload()
            {
                Text = "Cache is disabled. Check the HTTP headers"
            };
        }
    }
}

在“public void Configuration(IAppBuilder app)”方法中,我使用“app.Use()”方法向 Owin 配置添加了一个 lambda 函数。该 lambda 函数是一个 Owin 中间件。

  • lambda 函数的第一个参数是“IOwinContext”,我们可以使用此对象来修改所有 HTTP 请求的响应行为。
  • 第二个参数代表另一个中间件或一个动作方法。如果我们不想 Owin 继续处理请求,我们通常需要“return next()”来让它继续执行。

在此示例中,我在中间件中添加了禁用浏览器缓存的标头,以用于响应。除非被中断,否则中间件会为所有 HTTP 请求运行,因此标头会被添加到所有 HTTP 请求中。如果您运行该应用程序并访问 URL“https://:800/AConcrete/getAString”,您可以看到标头已添加到响应中。

C-Action-Filter (动作过滤器)

在上一个示例中,我们使用中间件为所有请求禁用浏览器缓存。但在某些情况下,我们不希望将标头添加到所有请求,而只想添加到某些控制器或动作方法。在这种情况下,可以使用 动作过滤器

using Microsoft.Owin.Hosting;
using Owin;
using System;
using System.Net.Http.Headers;
using System.Web.Http;
using System.Web.Http.Controllers;
using System.Web.Http.Filters;
    
namespace C_Action_Filter
{
    class Program
    {
        static void Main(string[] args)
        {
            WebApp.Start<Startup>("http://*:800/"); ;

            Console.WriteLine("C_Action_Filter started");
            Console.Write("Type any key to stop ... ");
            Console.Read();
        }
    }
    
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {

            HttpConfiguration config = new HttpConfiguration();
    
            config.MapHttpAttributeRoutes();
            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "{controller}/{action}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );
    
            app.UseWebApi(config);
        }
    }
    
    // The action filter to disable the browser caching
    public class NoCache : ActionFilterAttribute
    {
        public override void OnActionExecuting(HttpActionContext ctx)
        {
            base.OnActionExecuting(ctx);
        }
    
        public override void OnActionExecuted(HttpActionExecutedContext ctx)
        {
            // Add the cache control headers
            ctx.Response.Headers
                .Add("Cache-Control", "no-cache, no-store, must-revalidate");
            ctx.Response.Headers.Add("Pragma", "no-cache");
            ctx.Response.Content.Headers.Expires = DateTimeOffset.Now.AddDays(-365);
    
            base.OnActionExecuted(ctx);
        }
    }
    
    public class AConcreteController : ApiController
    {
        public class ResponsePayload
        {
            public string Text { get; set; }
        }
    
        [NoCache]
        [HttpGet]
        public ResponsePayload NoCacheContent()
        {
            return new ResponsePayload { Text = "The content should not be cached" };
        }
    
        [HttpGet]
        public ResponsePayload CacheableContent()
        {
            return new ResponsePayload { Text = "The content is cacheable" };
        }
    
    }
}

动作过滤器是“ActionFilterAttribute”类的子类。在此示例中,我在“NoCache”类中实现了一个动作过滤器。

  • 我们可以重写动作过滤器中的“OnActionExecuting()”和“OnActionExecuted()”方法。“OnActionExecuting()”方法在调用动作方法之前被调用,“OnActionExecuted()”方法在调用动作方法之后被调用。
  • 在“NoCache”类中,禁用浏览器缓存的 HTTP 标头被添加到响应中。

要将动作过滤器应用于动作方法,我们可以将类名注解在动作方法上。如果您希望动作过滤器应用于控制器中的所有动作方法,可以在控制器级别进行注解。在此示例中,如果您访问“https://:800/AConcrete/NoCacheContent”,您可以看到标头已添加到响应中。但是如果您访问“https://:800/AConcrete/CacheableContent”,则不会添加禁用浏览器缓存的标头。以下显示了对请求“https://:800/AConcrete/CacheableContent”的响应标头。

D-Static-Content (静态内容)

我们已经看到了 Owin 从动作方法提供 HTTP 请求的示例。但是,Owin 能够提供静态内容是理想的。要通过 Owin 提供静态内容,我们需要添加一个额外的 Nuget 包。

本示例的目标是配置 Owin 来提供“Static-content”文件夹中的“A-test-page.html”页面。

为了使“A-test-page.html”在生成输出文件夹中可用,我们需要右键单击“A-test-page.html”页面 -> 属性,将“Build Action”(生成操作)设置为“Content”(内容),并将“Copy to Output Directory”(复制到输出目录)设置为“Copy if newer”(如果更新则复制)。

using Microsoft.Owin.FileSystems;
using Microsoft.Owin.Hosting;
using Microsoft.Owin.StaticFiles;
using Owin;
using System;
    
namespace D_Static_Content
{
    /// <summary>
    /// In addition to the minimal Owin Nuget dependencies
    /// The "Microsoft.Owin.StaticFiles" Nuget package is needed
    /// </summary>
    class Program
    {
        static void Main(string[] args)
        {
            WebApp.Start<Startup>("http://*:800/");
    
            Console.WriteLine("D_Static_Content started");
            Console.Write("Type any key to stop ... ");
            Console.Read();
        }
    }
    
    class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            var path = "./Static-content";
    
            #if DEBUG
            path = "../../Static-content";
            #endif
    
            app.UseFileServer(new FileServerOptions
            {
                EnableDefaultFiles = true,
                FileSystem = new PhysicalFileSystem(path)
            });
        }
    }
}

为了让 Owin 能够提供静态内容,我们需要在“public void Configuration(IAppBuilder app)”方法中映射文件的物理位置。文件的路径相对于应用程序的 EXE 文件位置。

  • 默认情况下,该位置被映射到生成输出文件夹。
  • 在调试模式下,该位置被映射到 Visual Studio 项目中文件的位置。因为它们是静态文件,所以如果我们修改了静态文件并在调试应用程序时,我们不需要重新编译项目即可看到更改。

运行应用程序并从浏览器访问 URL“https://:800/A-test-page.html”,我们可以看到“A-test-page.html”页面已成功加载。

E-Cross-Domain (跨域)

Web 应用程序中的跨域问题是在进行 Ajax 调用时遇到的常见问题。这是一个 相对文档齐全的问题。但它也引起了很多混淆。为了支持跨域,Owin 实际上要求我们安装两个 Nuget 包。如果我有时间,我可能会写一篇专门的说明来讨论跨域问题。但在这篇说明中,我将只展示如何在不使用 Nuget 包的情况下实现跨域。

  • 在跨域问题的上下文中,域由 URL 识别。例如,当浏览器从“http://domainb.foo:8080/image.jpg”加载图片时,图片文件的域由“http://domainb.foo:8080”标识,其中包含端口号。
  • 当加载 HTML 内容的 URL 和发出 Ajax 调用的 URL 不在同一域时,浏览器会将 Ajax 调用视为跨域调用。
  • 当 Web 浏览器通过 Ajax 调用发出简单的跨域 GET 请求时,它会直接发出调用。但请求标头将有一个名为“Referer”的条目。“Referer”是发出 Ajax 调用的 Web 页面的域。如果 Web 服务器允许此请求,它需要添加一个与“Referer”匹配的“Access-Control-Allow-Origin”响应标头。当浏览器收到响应时,它会检查“Access-Control-Allow-Origin”标头。如果找到匹配项,它会将 Ajax 调用视为成功。否则,它将使 Ajax 请求失败。
  • 当 Web 浏览器发出涉及复杂数据或请求不是 GET,而是 POST、PUT 等的跨域 GET 请求时,它将首先向服务器发出一个 预检 OPTIONS 请求,以检查是否允许 Ajax 请求。服务器需要用适当的标头响应此 OPTIONS 请求,以告知浏览器允许的方法和选项。如果不允许该类型的 Ajax 请求,浏览器将停止并使 Ajax 请求失败。

在此示例中,我将使用“A-test-page.html”来进行一些 Ajax 调用以尝试跨域问题。

using Microsoft.Owin.FileSystems;
using Microsoft.Owin.Hosting;
using Microsoft.Owin.StaticFiles;
using Owin;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Web.Http;
    
namespace E_Cross_Domain
{
    /// <summary>
    /// In addition to the minimal Owin Nuget dependencies
    /// The following Nuget Packages may be useful for cross domain problems
    /// 1. "Microsoft.AspNet.WebApi.Cors"
    /// 2. "Microsoft.Owin.Cors"
    /// But this example does not use the Nuget packages
    /// </summary>
    class Program
    {
        static void Main(string[] args)
        {
            WebApp.Start<Startup>("http://*:700/");
    
            WebApp.Start<Startup>("http://*:800/");
            WebApp.Start<Startup>("http://*:900/");
    
            Console.WriteLine("E_Cross_Domain started");
            Console.Write("Type any key to stop ... ");
            Console.Read();
        }
    }
    
    class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            // Disable browser cache for all the requests for easy testing
            app.Use((ctx, next) =>
            {
                ctx.Response.Headers["Cache-Control"] = "no-cache, no-store, must-revalidate";
                ctx.Response.Headers["Pragma"] = "no-cache";
                ctx.Response.Headers["Expires"] = "-1";

                return next();
            });
    
            // Owin middle ware to allow cross domain Ajax calls
            // Add the permitted domain in the HashSet to allow cross domain Ajax
            HashSet<string> permitted_domains = new HashSet<string>();
            permitted_domains.Add("https://:900");
    
            app.Use((ctx, next) =>
            {
                var request = ctx.Request;
                var response = ctx.Response;
    
                // If the request has a referer, check if we allow the referer to
                // make the call. If we do, send the "Access-Control-Allow-Origin" header.
                var referer = request.Headers["Referer"];
                if (referer != null)
                {
                    Uri refUri = new Uri(referer);
                    string domainString = refUri.Scheme + "://" + refUri.Authority;
    
                    if (permitted_domains.Contains(domainString))
                    {
                        response.Headers["Access-Control-Allow-Origin"] = domainString;
                    }
                }
    
                // Respond to the browser for preflighted requests
                if (request.Method == "OPTIONS")
                {
                    response.Headers["Access-Control-Allow-Methods"] = "GET, POST";
                    response.Headers["Access-Control-Allow-Headers"] = "Content-Type, Accept";
                    response.Headers["Access-Control-Max-Age"] = "86400";
    
                    return Task.Run(() => { });
                }
    
                return next();
    
            });
    
            // 2. Configure static files
            var path = "./Static-content";
    
            #if DEBUG
            path = "../../Static-content";
            #endif
    
            app.UseFileServer(new FileServerOptions
            {
                EnableDefaultFiles = true,
                FileSystem = new PhysicalFileSystem(path)
            });
    
            // 3. Configure the web apis
            HttpConfiguration config = new HttpConfiguration();
    
            config.MapHttpAttributeRoutes();
            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "{controller}/{action}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );
    
            app.UseWebApi(config);
    
        }
    }
    
    public class AConcreteController : ApiController
    {
        [HttpGet]
        public object getTimeByGET()
        {
            return new { Time = DateTime.Now };
        }
    
        [HttpPost]
        public object getTimeByPOST()
        {
            return new { Time = DateTime.Now };
        }
    
        [HttpPut]
        public object getTimeByPUT()
        {
            return new { Time = DateTime.Now };
        }
    }
}
  • 在此示例中,我们将 Owin 配置为监听三个端口“700”、“800”和“900”。在实验中,我将使用“700”向“AConcreteController”控制器中实现的动作方法发出 Ajax 调用。“800”和“900”用于加载“A-test-page.html”页面。
  • “AConcreteController”类实现了三个动作方法。每个方法只接受一个 HTTP 方法,可以是 GET、POST 或 PUT。
  • 添加了一个 Owin 中间件来控制跨域 Ajax 访问。它仅在请求“Referer”为“https://:900”时发送“Access-Control-Allow-Origin”。当收到 预检 OPTIONS 请求时,它会告知浏览器仅允许“GET”和“POST”方法。

“A-test-page.html”页面有三个按钮,每个按钮向相应的动作方法发出一个 Ajax 调用。

<!DOCTYPE html>
    
<html>
<head>
    <meta charset="utf-8" />
    <title>A static HTML page</title>
    
    <style type="text/css">
        body {
            font-family: Verdana;
            font-weight: 600;
        }
        button {
            width: 150px;
        }
    </style>
    
    <script type="text/javascript">
        window.onload = function () {
            let Ajax = function (method, api) {
                // Hardcoded to call the port number 700
                let url = 'https://:700/' + api;
    
                let xhr = new XMLHttpRequest();
                xhr.open(method, url);
                xhr.setRequestHeader('Content-Type', 'application/json');
    
                xhr.onload = function () {
                    if (xhr.status === 200) {
                        alert(xhr.responseText);
                    }
                    else {
                        alert('Request failed status = ' + xhr.status);
                    }
                };
    
                xhr.onerror = function () {
                    alert('Failed!');
                }
    
                return xhr;
            };
    
            document.getElementById('btnGET')
                .onclick = function () {
                    Ajax("GET", "AConcrete/getTimeByGET").send();
            };
    
            document.getElementById('btnPOST')
                .onclick = function () {
                    Ajax("POST", "AConcrete/getTimeByPOST").send();
            };
    
            document.getElementById('btnPUT')
                .onclick = function () {
                    Ajax("PUT", "AConcrete/getTimeByPUT").send();
            };
    
        };
    </script>
</head>
<body>
    <div><button id="btnGET">GET METHOD</button></div>
    <div><button id="btnPOST">POST METHOD</button></div>
    <div><button id="btnPUT">PUT METHOD</button></div>
</body>
</html>

如果我们启动应用程序并通过 URL“https://:800/A-test-page.html”加载“A-test-page.html”,您会发现所有 Ajax 调用都因缺少“Access-Control-Allow-Origin”标头而失败。如果您通过“https://:900/A-test-page.html”访问“A-test-page.html”,您会发现 GET 和 POST 方法都成功了,但 PUT 方法失败。以下显示了当页面通过端口号“900”加载时,PUT Ajax 调用失败。

F-Run-As-Windows-Service (作为 Windows 服务运行)

在本说明中,我们已经看到了许多将 Owin 应用程序作为控制台应用程序启动的示例。在许多情况下,有必要将 Owin 应用程序部署为 Windows 服务,以便它可以在计算机启动时自动启动。准备此示例时,我参考了 此示例。虽然我没有完全遵循他的方法,但我发现它写得非常好且有帮助。要创建 Windows 服务,您需要向项目中添加“System.ServiceProcess”引用。

“Program.cs”文件实现了一个“ServiceBase”类的子类。Visual Studio 会注意到它是一个“ServiceBase”的子类,它会尝试控制它。如果您想查看此文件的源代码,需要右键单击它并选择“View Code”(查看代码)选项。

using Microsoft.Owin.Hosting;
using Owin;
using System;
using System.ServiceProcess;
using System.Web.Http;
    
namespace F_Run_As_Windows_Service
{
    public class WindowsService : ServiceBase
    {
        private static void StartOwinService()
        {
            WebApp.Start<Startup>("http://*:800/");
        }
    
        static void Main()
        {
            if (Environment.UserInteractive)
            {
                StartOwinService();
    
                Console.WriteLine("F_Run_As_Windows_Service started");
                Console.Write("Type any key to stop ... ");
                Console.Read();
            }
            else
            {
                ServiceBase.Run(new WindowsService());
            }
        }
    
        public WindowsService()
        {
            this.CanHandlePowerEvent = false;
            this.CanHandleSessionChangeEvent = false;
            this.CanPauseAndContinue = false;
            this.CanShutdown = false;
            this.CanStop = true;
        }
    
        protected override void OnStart(string[] args)
        {
            StartOwinService();
            base.OnStart(args);
        }
    
        // Nothing to do when service stops
        protected override void OnStop() { base.OnStop(); }
        protected override void Dispose(bool disposing) { base.Dispose(disposing); }
    }
    
    class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            HttpConfiguration config = new HttpConfiguration();
    
            config.MapHttpAttributeRoutes();
            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "{controller}/{action}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );
    
            app.UseWebApi(config);
        }
    }
    
    public class ResponsePayload
    {
        public string Text { get; set; }
    }
    
    public class AConcreteController : ApiController
    {
        public ResponsePayload getAString()
        {
            return new ResponsePayload()
            {
                Text = "Owin service hosted in Wnd service"
            };
        }
    }
}

这是一个最小的 Windows 服务,也是一个控制台应用程序。Owin 服务在静态方法“StartOwinService”中启动。

  • 在“static void Main()”方法中,如果“Environment.UserInteractive”为 true,则表示我们正在调试。它将作为控制台应用程序启动,因此我们可以运行 Owin 服务而无需将其部署为 Windows 服务。
  • 如果“Environment.UserInteractive”为 false,则表示我们已将其部署为 Windows 服务。Owin 服务将在 Windows 服务的“OnStart”事件中启动。

部署 Windows 服务

编译应用程序后,我们可以使用“sc.exe”将其部署为 Windows 服务。“sc.exe”在所有 Windows 机器上都可用。您可能需要以“管理员”身份启动命令提示符窗口来处理 Windows 服务。您可以发出以下命令来部署和启动 Windows 服务。

sc create OService binPath= "Abosolute-path-to-the-exe" displayName= "O Service"
sc start OService
  • “OService”是服务的名称。您可以为您的服务选择任何名称,但名称中不应包含空格。
  • “binPath”是服务的 exe 文件的路径。如果没有特殊需求,我建议在此处使用绝对路径。
  • “displayName”是服务在 Windows 服务管理器中显示的名称。

如果您正确部署和启动了服务,您应该会在 Windows 服务管理器中看到“O Service”。如果您现在在 POSTMAN 中使用 GET 方法加载 URL“https://:800/AConcrete/getAString”,您应该看到您的 Owin 服务作为 Windows 服务运行良好。

如果您想删除您的 Windows 服务,您可以发出以下命令。

sc stop OService
sc delete OService

关注点

  • 这是一篇关于 Owin 托管服务的说明。
  • 在本说明中,我提供了以下主题的示例:
    • 如何创建一个最小的 Owin 服务;
    • 如何在 Owin 中创建和使用中间件;
    • 如何在 Owin 中创建和使用动作过滤器;
    • 如何在 Owin 中托管静态文件;
    • 如何在 Owin 中解决跨域 Ajax 调用问题;
    • 如何将 Owin 服务部署为 Windows 服务。
  • 希望您喜欢我的博文,并希望这篇笔记能以某种方式帮助您。

历史

首次修订 - 2017 年 6 月 18 日。

© . All rights reserved.