• 热门专题

OWIN的理解和实践(二) Host和Server的开发

作者:Charlie.Zheng  发布日期:2015-03-24 20:54:00
  • 对于开发人员来说,代码就是最好的文档,如上一篇博文所说,下面我们就会基于Kanata项目的一些具体调用代码,来进一步深入理解OWIN的实现和作用.

    今天我们先针对Host和Server来实现一个简单的应用.

    我们的开发环境是:  VS2013 Update 3,  .Net Framework 4.5.1

    Host开发

    如上篇博文提及,Host具有如下特点:

    实现一个宿主进程 负责Server的启动和关闭 负责Middleware和Application的装载

    最简单的宿主进程就是Console Application,那么我们从建立Console程序开始

     

    注意这个程序和它的入口类(一般是Program.cs)就是我们所说的Host宿主进程的实现.

    而具体的Host和Server的实现我们就需要借助Kanata项目的实现了.

    首先通过Nuget获取Kanata的Host实现. 包名为: Microsoft.Owin.Hosting

     

    注: 目前版本为3.0.1, Owin的2个核心组件:  Owin和Microsoft.Owin会被同时载入.

    WebApp.Start

    Host的主要用途是启动和关闭Server, 这个功能的实现类就是在Microsoft.Owin.Hosting下的WebApp类, 请看类结构:

    我们可以看到,WebApp只有若干个Start函数,辅助于StartOptions类,依靠这2个类,就能完成Host对Server的启动和关闭.

    Start函数有好几个重载,我们来看一个最为典型的实现. (其他实现大同小异,如果要使用请参阅相关文档)

    public static System.IDisposable Start(Microsoft.Owin.Hosting.StartOptions options, System.Action<IAppBuilder> startup)

    Options参数定义了Server启动所需的参数. Startup参数是一个以Owin.IAppbuilder接口为参数的函数,通过这个函数,完成对Server所需Middleware的加载工作,这也是Host的关键作用之一! 函数返回一个实现IDisposable接口的类, 可以预见的是,当这个类Dispose的时候,被这个函数启动的Server也会同时关闭和消亡.

    StartOptions

    我们先来看下这个StartOptions中2个比较关键的属性:

    public System.Collections.Generic.IList<string> Urls { get; }

    Urls参数是以http标准url为格式字符串来定义Server监听的HostName和Port.

    标准格式是 http(s)://hostname:port ; 比如 http://localhost:8080 ;  https://192.168.1.1:9000;

    注意,Urls可以加多个,表示支持不同的hostname和port映射. 另外, 还支持http://*:9000 这样的格式,表示映射所有HostName,这个和IIS映射配置其实是类似的.

    public string ServerFactory { set; get; }

    关键的来了,这个就是Server实现类的assembly name, 大家不难想到,通过这个属性,Host和Server是完全解耦的. 我们的这个Host可以和任何符合Owin接口的Server实现进行组合. 当然,目前还是使用自家的Server实现,请看下节.

    Server实现和引用

    Http Server并不是一两句代码可以实现的, 这里我们还是继续站在Kanata的肩膀上,借用它的Server实现.  他的Server实现包名为 :  Microsoft.Owin.Host.HttpListener (我认为这里的Host改名为Server更加贴切)

    首先还是使用Nuget获取该Server组件

     

    安装,并引入项目,有了Server的实现,下面我们来完成StartOptions的定义代码:

                //初始化StartOptions参数
                StartOptions options = new StartOptions();
                //服务器Url设置
                options.Urls.Add('http://localhost:9000');
                options.Urls.Add('http://192.168.1.1:8080');
                //Server实现类库设置
                options.ServerFactory = 'Microsoft.Owin.Host.HttpListener';

    需要注意的是,我这里特地放了2个port不同的地址,这2个Url都能起到效果; 另外Microsoft.Owin.Host.HttpListener 其实是默认的Host ServerFatory实现(最后一行代码可以省略); 但我们必须理解,这里是可以解耦的,我们完全可以桥接其他的Server实现.

    Startup函数和使用

    Startup函数非常的简单,就是一个只有一个没有返回值的,只有一个Owin.IAppBuilder参数的函数(函数名任意,不一定要叫Startup). 如以下代码:

            private static void Startup(Owin.IAppBuilder app)
            {
                //这里通过app句柄,为当前Server加入所有需要的middleware
            }

    在这个函数中,通过app参数提供的句柄,一步步的加入Server所需要的所有Middleware,当然这些Middleware都是可自由组合,自由拆卸的,非常的灵活.

    Server的启动和关闭

    有了Options和Startup函数,我们就可以启动我们的Server了,整合的代码如下:

            /// <summary>
            /// Owin Host 主进程入口函数
            /// </summary>
    
            static void Main()
            {
                //初始化StartOptions参数
                StartOptions options = new StartOptions();
    
                //服务器Url设置
                options.Urls.Add('http://localhost:9000');
                options.Urls.Add('http://192.168.1.1:8080');
    
                //Server实现类库设置
                options.ServerFactory = 'Microsoft.Owin.Host.HttpListener';
       
                //以当前的Options和Startup启动Server
                using (WebApp.Start(options, Startup))
                {
                    //显示启动信息,通过ReadLine驻留当前进程
                    Console.WriteLine('Owin Host/Server started,press enter to exit it...');
                    Console.ReadLine();
                }//Server在Dispose中关闭
            }
    
            private static void Startup(Owin.IAppBuilder app)
            {
                //这里通过app句柄,为当前Server加入所有需要的middleware
            }

    Server的关闭很简单,当using的结尾触发Dispose时,该Server被自动关闭.

    Server是独立线程运行的,所以宿主进程必须驻留,这里用Console.ReadLine()驻留当前线程,保证Server长期运行.

    其他注意点

    很多机器上出现权限不够情况,请用管理员账号运行VS2013. 用浏览器访问2个地址时发现可以联通,但Reponse为空,这符合上一篇中说提到的: Server仅仅是一个空的实现,在没有任何Middleware装载的情况下(我们的Startup函数为空),所有的Request都只能获得一个空的Response这一论点. 加入不同的Middleware能够实现不同的Reponse返回,这个将在以后的篇幅中继续讨论. 尽量用Nuget获取我们需要的组件包,以保证组件正确性和版本统一.

     

    总结下,我们开发了一个以Console Application为宿主进程的程序,通过Kanata的Host实现Microsoft.Owin.Hosting启动了它自身的Server实现 Microsoft.Owin.Host.HttpListener, 目前没有加入任何Middleware和Application实现.

    这里再罗嗦一句, Kanata的Host和Server实现完全可以被自己或者第三方的实现所取代,前提是,符合OWIN的标准.

延伸阅读:

About IT165 - 广告服务 - 隐私声明 - 版权申明 - 免责条款 - 网站地图 - 网友投稿 - 联系方式
本站内容来自于互联网,仅供用于网络技术学习,学习中请遵循相关法律法规