• Nancy.Host的Web应用


    Nancy.Host实现脱离iis的Web应用

    本篇将介绍如何使用Nancy.Host实现脱离iis的Web应用,在开源任务管理平台TaskManagerV2.0代码里面已经使用了Nancy.Host实现自宿主的Web应用。学习Nancy之前最好了解一下ASP.NET MVC,因为Nancy和MVC实在是太相似了。

    阅读目录

    Nancy介绍

        Nancy是一个轻量级的用来创建基于HTTP的服务的框架,该框架的可以运行在.net或者mono上。 Nancy处理和mvc类似的DELETEGETHEADOPTIONSPOSTPUT,PATCH请求,如果你有mvc开发的经验相信可以快速入门。最重要的一点可以让你的Web应用脱离IIS的束缚。

    复制代码
    public class Module : NancyModule
    {
        public Module()
        {
            Get["/greet/{name}"] = x => {
                return string.Concat("Hello ", x.name);
            };
        }
    }
    复制代码

    特征

    1. 自底向上全套都是新构建的,移除了对其他框架的引用和限制。
    2. Run anywhere. Nancy 能够在ASP.NET/IIS,OWIN,Self-hosting中运行。
    3. 集成支持各种View engine(Razor, Spark, dotLiquid, SuperSimpleViewEngine...)

    资源

        Github:https://github.com/NancyFx/Nancy  官网:http://nancyfx.org  使用介绍:http://liulixiang1988.github.io/nancy-webkuang-jia.html

    创建第一个应用

      1.创建控制台程序,引用相关Package

      使用Nuget安装Nancy,Nancy.Hosting.Self,Nancy.Viewengines.Razor,Newtonsoft.Json四个Package

      

       2.监听端口

    复制代码
    class Program
        {
            static void Main(string[] args)
            {
                try
                {
                    int port = 9000;
                    string url = string.Format("http://localhost:{0}", port);
                    var _host = new NancyHost(new Uri(url));
                    _host.Start();
                    Process.Start(url);
                    Console.WriteLine("站点启动成功,请打开{0}进行浏览",url);
                }
                catch (Exception ex)
                {
                    Console.WriteLine("站点启动失败:"+ex.Message);
                }
                Console.ReadKey();
            }
        }                                                                                                                        
    复制代码
       3.创建模块和视图
      我们这里使用Razor视图引擎,熟悉MVC的应该很清楚怎么使用这里只做简单演示
      新建控制器文件夹Modules,视图文件夹Views
     
     创建控制器
    复制代码
    public class HomeModule : NancyModule
        {
            public HomeModule()
            {
                //主页
                Get["/"] = r =>
                {
                    return Response.AsRedirect("/Home/Index");
                };
    
                //主页
                Get["/Home/Index"] = r =>
                {
                    return View["index", "测试站点"];
                };
    
                ///桌面
                Get["/DestTop"] = r =>
                {
                    return View["DestTop"];
                };
            }
        }
    复制代码

     小知识点:Nancy里面的所有控制器都需要继承NancyModule类,类比MVC的控制器都需要继承Controller

    创建视图

    新建index.cshtml视图内容如下:

    复制代码
    @inherits Nancy.ViewEngines.Razor.NancyRazorViewBase
    
    @{
        ViewBag.Title = @Model;
    }
    
    @section style{
       
    }
    
    我是第一个Nancy应用
    
    
    @section scripts{
        <script>
          
        </script>
    }
    复制代码

    至此一个简单的应用完成了,运行项目后你会发现提示找不到视图index,是因为index视图没有拷贝到 binDebug目录下,添加视图的时候需要手工设置文件属性->始终复制到输出目录。如果嫌这样设置太麻烦可以采取我后面提供的一种方案。

     

    使用技巧

      仅上面这点东西做一个Web应用是完全不够的,下面讲解一下进阶内容和使用小技巧。

      1.使用CSS和JS等静态资源

      要想在视图里面使用静态资源需要设置允许访问的静态资源类型,通过继承DefaultNancyBootstrapper类重写ConfigureConventions方法

    复制代码
    public class CustomBootstrapper : DefaultNancyBootstrapper
        {
            protected override void ApplicationStartup(TinyIoCContainer container, IPipelines pipelines)
            {
                base.ApplicationStartup(container, pipelines);
    
                //pipelines.BeforeRequest += ctx =>
                //{
                //    return null;
                //};
    
                pipelines.AfterRequest += ctx =>
                {
                    // 如果返回状态吗码为 Unauthorized 跳转到登陆界面
                    if (ctx.Response.StatusCode == HttpStatusCode.Unauthorized)
                    {
                        ctx.Response = new RedirectResponse("/login?returnUrl=" + Uri.EscapeDataString(ctx.Request.Path));
                    }
                    else if (ctx.Response.StatusCode == HttpStatusCode.NotFound)
                    {
                        ctx.Response = new RedirectResponse("/Error/NotFound?returnUrl=" + Uri.EscapeDataString(ctx.Request.Path));
                    }
                };
    
                pipelines.OnError += Error;
            }
    
            protected override IRootPathProvider RootPathProvider
            {
                get { return new CustomRootPathProvider(); }
            }
    
            /// <summary>
            /// 配置静态文件访问权限
            /// </summary>
            /// <param name="conventions"></param>
            protected override void ConfigureConventions(NancyConventions conventions)
            {
                base.ConfigureConventions(conventions);
    
                ///静态文件夹访问 设置 css,js,image
                conventions.StaticContentsConventions.AddDirectory("Content");
            }
    
            protected override void ConfigureApplicationContainer(TinyIoCContainer container)
            {
                base.ConfigureApplicationContainer(container);
                //替换默认序列化方式
                container.Register<ISerializer, CustomJsonNetSerializer>();
            }
    
            private dynamic Error(NancyContext context, Exception ex)
            {
                //可以使用log4net记录异常 ex 这里直接返回异常信息
                return ex.Message;
            }
        }
    复制代码

     这里设置的根目录下的Content文件夹下所有文件都可以被访问,我们可以将所有静态资源放在该文件夹下

      2.使用视图模版

     视图模版使用方式和mvc的一模一样,在视图文件夹下创建_ViewStart.cshtml视图,内容如下

    @{
        Layout = "/Shared/_Layout.cshtml";
    }
    _Layout.cshtml里面放置页面公共的内容比如公共css和js,定义相关占位符
    复制代码
    @inherits Nancy.ViewEngines.Razor.NancyRazorViewBase
    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=0" />
        <meta name="apple-mobile-web-app-capable" content="yes">
        <meta name="apple-mobile-web-app-status-bar-style" content="black">
        <meta name="format-detection" content="telephone=no">
        <title>@ViewBag.Title</title>
        <link rel="shortcut icon" type="image/x-icon" href="~/Content/Image/favicon.ico">
        <link href="~/Content/Css/style.css" rel="stylesheet">
        @RenderSection("style", required: false)
    </head>
    <body>
        @RenderBody()
    
        <script src="~/Content/Scripts/jquery-1.10.2.min.js"></script>
        @RenderSection("scripts", required: false)
    </body>
    </html>
    复制代码

       3.控制器返回JSON值控制

       默认Nancy使用的是自己内置的JSON序列化库,个人倾向于使用JSON.NET库。所以通过设置替换成了JSON.NET。在CustomBootstrapper的ConfigureApplicationContainer容器里面替换了序列化库

    复制代码
        /// <summary>
        /// 使用Newtonsoft.Json 替换Nancy默认的序列化方式
        /// </summary>
        public class CustomJsonNetSerializer : JsonSerializer, ISerializer
        {
            public CustomJsonNetSerializer()
            {
                ContractResolver = new DefaultContractResolver();
                DateFormatHandling = DateFormatHandling.IsoDateFormat;
                Formatting = Formatting.None;
                NullValueHandling = NullValueHandling.Ignore;
            }
    
            public bool CanSerialize(string contentType)
            {
                return contentType.Equals("application/json", StringComparison.OrdinalIgnoreCase);
            }
    
            public void Serialize<TModel>(string contentType, TModel model, Stream outputStream)
            {
                using (var streamWriter = new StreamWriter(outputStream))
                using (var jsonWriter = new JsonTextWriter(streamWriter))
                {
                    Serialize(jsonWriter, model);
                }
            }
    
            public IEnumerable<string> Extensions { get { yield return "json"; } }
        }
    复制代码

        4.返回文件

    复制代码
            Get["/Home/Download"] = r =>
                {
                    string path = AppDomain.CurrentDomain.BaseDirectory+@"ContentUpFile使用说明.docx";
                    if (!File.Exists(path))
                    {
                        return Response.AsJson("文件不存在,可能已经被删除!");
                    }
                    var msbyte = default(byte[]);
                    using (var memstream = new MemoryStream())
                    {
                        using (StreamReader sr = new StreamReader(path))
                        {
                            sr.BaseStream.CopyTo(memstream);
                        }
                        msbyte = memstream.ToArray();
                    }
    
                    return new Response()
                    {
                        Contents = stream => { stream.Write(msbyte, 0, msbyte.Length); },
                        ContentType = "application/msword",
                        StatusCode = HttpStatusCode.OK,
                        Headers = new Dictionary<string, string> {
                            { "Content-Disposition", string.Format("attachment;filename={0}", HttpUtility.UrlPathEncode(Path.GetFileName(path))) },
                            {"Content-Length",  msbyte.Length.ToString()}
                        }
                    };
                };
    复制代码
        5.视图找不到解决方案
       由于需要将视图文件和静态资源文件拷贝到bin目录下除了设置文件生成属性还可以通过项目生成后事件解决
       
    批处理脚本如下
    rd/s/q $(TargetDir)Content
    rd/s/q $(TargetDir)Views
    xcopy $(ProjectDir)Content*.* $(TargetDir)Content /s/d/r/y
    xcopy $(ProjectDir)Views*.* $(TargetDir)Views /s/d/r/y
     

    总结

          本篇要介绍的内容到此结束了,源代码下载地址:http://files.cnblogs.com/files/yanweidie/NancyConsole.rar,更多关于Nancy的使用可以下载TaskManager源码进行研究http://code.taobao.org/svn/TaskManagerPub/Branch。下一篇介绍如何使用MEF实现通用的参数配置管理。

  • 相关阅读:
    php数据缓存到文件类设计
    php静态文件缓存示例
    php array_merge和“+”的区别和使用《细说php2》
    kafka环境安装及简单使用(单机版)
    Protobuf的上手使用
    Java8新特性概览
    Mock测试框架(Mockito为例)
    Java序列化与反序列化
    系统/项目环境搭建
    关于Tomcat服务器中的协议及请求过程
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/5488220.html
Copyright © 2020-2023  润新知