使用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視圖沒有拷貝到 bin\Debug目錄下,添加視圖的時候需要手工設置文件屬性->始終復制到輸出目錄。如果嫌這樣設置太麻煩可以采取我后面提供的一種方案。

 

使用技巧

  僅上面這點東西做一個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+@"\Content\UpFile\使用說明.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實現通用的參數配置管理。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM