你的位置:首页 > ASP.net教程

[ASP.net教程]Nancy之基于Nancy.Hosting.Aspnet的小Demo

近来学习了一下Nancy这个框架,感觉挺好用的,就写篇简单的文章记录一下大致用法,由于是刚接触,写的代码

可能不规范,也没有具体的分层。。莫吐槽。。。

Nancy的官网:http://nancyfx.org/

GitHub地址:https://github.com/NancyFx/Nancy

Nancy在文档的介绍 -- 轻量级

" Nancy is a lightweight, low-ceremony, framework for building HTTP based services on .NET and Mono. "

Nancy有多种Hosting:

  Hosting Nancy with ASP.NET
  Hosting Nancy with WCF
  Hosting Nancy with Azure
  Hosting Nancy with OWIN
            Web (Katana)
            Self Hosting
            Environment Variables
            Conditional Pass-through
  Hosting Nancy with Umbraco
  Hosting Nancy with Nginx on Ubuntu
  Hosting Nancy with FastCgi
  Self Hosting Nancy
  Implementing a Host
  Accessing the client certificate when using SSL

本文写的Demo是基于Hosting Nancy with ASP.NET。

开发环境 :win 10 + VS2015 Community + SqlServer 2012

废话不多说,开始正题:

 一、新建一个空的asp.net项目

建好之后空空如也

二、通过NuGet添加Nancy相关的Packages

    

主要是Nancy、Nancy.Hosting.Aspnet、Nancy.Viewengines.Razor这三个。其版本依次为1.4.3、1.4.1、1.4.3

我这里选择的视图引擎是Razor,习惯了,你们可以选择其他,这个问题不大。

三、更新一下Razor

默认安装Nancy.Viewengines.Razor之后,它会安装 Microsoft.AspNet.Razor.2.0.30506.0,我们用的是最新版的3.2.3

在NuGet通过已安装的Packages来更新

到这里,基本的工作已经OK了。

这里用到了Dapper,所以我也添加了它的引用。

注:这里是通过NuGet安装的,所以它也在web.config里生成了一些配置。如果是手动添加引用的,注意要修改web.config。

四、加入css和javascript文件

允许我偷偷懒,这里的我是直接copy一般新建mvc项目的,就连页面布局也是用的新建项目的模板。。

五、新建Moudles、Models、ViewModels、Views四个文件夹。

Modules-->相当于MVC中的Controllers文件夹

Models-->存放模型

ViewModels-->存放视图模型

Views-->存放视图

六、在Views下面建一个布局页 _Layout.cshtml

就新建的mvc模板copy过来,稍加修改

 1 @inherits Nancy.ViewEngines.Razor.NancyRazorViewBase<dynamic> 2 <!DOCTYPE html> 3 <html> 4 <head> 5   <meta charset="utf-8" /> 6   <meta name="viewport" content="width=device-width, initial-scale=1.0"> 7   <title>@ViewBag.Title - Catcher's NancyDemo</title> 8   <link href="~/Content/bootstrap.min.css" rel="stylesheet" /> 9   <link href="~/Content/Site.css" rel="stylesheet" />  10   <link rel="shortcut icon" href="~/favicon.ico" />11 </head>12 <body>13   <div class="navbar navbar-inverse navbar-fixed-top">14     <div class="container">15       <div class="navbar-header">16         <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">17           <span class="icon-bar"></span>18           <span class="icon-bar"></span>19           <span class="icon-bar"></span>20         </button>21         <a href="http://www.cnblogs.com//" class="navbar-brand">NancyDemo</a>22       </div>23       <div class="navbar-collapse collapse">24         <ul class="nav navbar-nav">25           <li><a href="http://www.cnblogs.com//">首页</a></li>26           <li><a href="http://www.cnblogs.com//home/about">关于我们</a></li>27           <li><a href="http://www.cnblogs.com//home/contact">联系我们</a></li>28           <li><a href="http://www.cnblogs.com//movie/">电影</a></li>29           <li><a href="http://www.cnblogs.com//movie-type/">类型</a></li>30         </ul>31       </div>32     </div>33   </div>34   <div class="container body-content">35     @RenderBody()36     <hr />37     <footer>38       <p>&copy; @DateTime.Now.Year - My ASP.NET Application</p>39     </footer>40   </div>41   <script src="~/Scripts/jquery-1.10.2.min.js"></script>42   <script src="~/Scripts/bootstrap.min.js"></script>43 </body>44 </html>

_Layout.cshtml

七、在Modules下新建一个HomeModule.cs,具体如下:

 1 public class HomeModule : NancyModule 2   { 3     public HomeModule() 4     { 5       Get["/"] = _ => ShowHomePage(); 6       Get["/home/about"] = _ => ShowAboutPage(); 7       Get["/home/contact"] = _ => ShowContactPage(); 8     } 9 10     private dynamic ShowContactPage()11     {12       return View["Contact"];13     }14 15     private dynamic ShowAboutPage()16     {17       return View["About"];18     }19 20     private dynamic ShowHomePage()21     {22       return View["Index"];23     }24   }

HomeModule.cs

同时在Views文件夹下面新建一个Home的子文件夹,在把mvc模板中的Index.cshtml,About.cshtml,Contact.cshtml

copy过来稍加修改

 1 @inherits Nancy.ViewEngines.Razor.NancyRazorViewBase<dynamic> 2 @{ 3   ViewBag.Title = "首页"; 4   Layout = "Views/_Layout.cshtml"; 5 } 6 <div class="jumbotron"> 7   <h1>NancyDemo</h1> 8   <p class="lead">Nancy is a lightweight, low-ceremony, framework for building HTTP based services on .NET and Mono. The goal of the framework is to stay out of the way as much as possible and provide a super-duper-happy-path to all interactions.</p> 9   <p><a href="http://nancyfx.org/" class="btn btn-primary btn-lg">Learn more &raquo;</a></p>10 </div>

Index.cshtml
1 @inherits Nancy.ViewEngines.Razor.NancyRazorViewBase<dynamic>2 @{3   ViewBag.Title = "About";4   Layout = "Views/_Layout.cshtml";5 }6 <h2>@ViewBag.Title.</h2>7 <p>Use this area to provide additional information.</p>

About.cshtml
 1 @inherits Nancy.ViewEngines.Razor.NancyRazorViewBase<dynamic> 2 @{ 3   ViewBag.Title = "Contact"; 4   Layout = "Views/_Layout.cshtml"; 5 } 6 <h2>@ViewBag.Title.</h2> 7  8 <address> 9   One Microsoft Way<br />10   Redmond, WA 98052-6399<br />11   <abbr title="Phone">P:</abbr>12   425.555.010013 </address>14 15 <address>16   <strong>Support:</strong>  <a href="mailto:[email protected]">[email protected]</a><br />17   <strong>Marketing:</strong> <a href="mailto:[email protected]">[email protected]</a>18 </address>

Contact.cshtml

然后F5,跑一下

     

已经能跑起来了。

下面就是结合数据库了。

八、在Models下面建两个类

 1 public class Movie 2   { 3     public int MovieId { get; set; } 4  5     public string MovieName { get; set; } 6  7     public int MovieTypeId { get; set; } 8  9     public DateTime MovieAddTime { get; set; }10 11     public virtual MovieType MovieType { get; set; }12 13     public Movie()14     {15       MovieAddTime = DateTime.Now;16     }17   }

Movie.cs
 1   public class MovieType 2   { 3     public MovieType() 4     { 5       Movies = new HashSet<Movie>(); 6     } 7  8  9     public int TypeId { get; set; }10 11     public string TypeName { get; set; }12 13     public virtual ICollection<Movie> Movies { get; set; }14   }

MovieType.cs

以Movie表为例,继续下面的工作。

九、由于movie表中的数据展示,抽取出应该有的视图模型

在ViewModels文件夹下面建立MovieViewModel.cs、MovieListViewModel.cs

 1   public class MovieViewModel 2   { 3     public int MovieId { get; set; } 4  5     public string MovieName { get; set; } 6  7     public int MovieTypeId { get; set; } 8  9     public string MovieTypeName { get; set; }10 11     public DateTime MovieAddTime { get; set; }12   }

MovieViewModel.cs
1   public class MovieListViewModel2   {3     public IEnumerable<MovieViewModel> Movies { get; set; }4   }

MovieListViewModel.cs

十、现在就该写写类似mvc控制器的东西了,在Modules文件夹下建立MovieModule.cs

把数据提取出来

 1   public class MovieModule : NancyModule 2   { 3     public MovieModule() : base("/movie") 4     { 5       Get["/"] = _ => ShowMovieIndexPage();       6     } 7  8     private readonly string _sqlconnection = 9         "Data Source=192.168.0.71;Initial Catalog=NancyDemo;User Id=sa;Password=dream_time1314;";10 11     public SqlConnection OpenConnection()12     {13       SqlConnection connection = new SqlConnection(_sqlconnection);14       connection.Open();15       return connection;16     }17   18     private dynamic ShowMovieIndexPage()19     {20       using (IDbConnection conn = OpenConnection())21       {22         string getAllMoviesStoredProcedure = @"up_GetAllMovies";23         MovieListViewModel viewModel = new MovieListViewModel24         {25           Movies = conn.Query<MovieViewModel>(getAllMoviesStoredProcedure,26           null, null, true, null, CommandType.StoredProcedure)27         };28         return View["Index", viewModel];29       }30     }31   }

MovieModule.cs

然后就去编写视图

 在Views下面新建一个Movie文件夹,用于存放相关视图

 1 @inherits Nancy.ViewEngines.Razor.NancyRazorViewBase<MovieDemo.ViewModels.MovieListViewModel> 2 @{ 3   Layout = "Views/_Layout.cshtml"; 4   ViewBag.Title = "电影列表"; 5 } 6 <a href="http://www.cnblogs.com//movie/create">添加</a> 7 <div> 8   <table class="table"> 9     <tr>10       <th>11         #12       </th>13       <th>14         电影名称15       </th>16       <th>17         电影类型18       </th>19       <th>20         添加时间21       </th>22       <th></th>23     </tr>24     @foreach (var item in Model.Movies)25       {26       <tr>27         <td>28           @item.MovieId29         </td>30         <td>31           @item.MovieName32         </td>33         <td>34           @item.MovieTypeName35         </td>36         <td>37           @item.MovieAddTime38         </td>39         <td>40           <a href="http:[email protected]">修改</a>41           <a class="delete" href="http:[email protected]">删除</a>42         </td>43       </tr>44     }45   </table>46 </div>

Index.cshtml

F5跑一下

OK!

然后就是修改某条数据,

在MovieModule.cs 的构造函数中添加 

1      Get["/edit/{movieId}"] = _ => ShowMovieEditPage(_.movieId);2       Post["/edit/{movieId}"] = _ =>3       {4         var movie = this.Bind<Movie>();5         return MovieEdit(movie);6       };

然后添加ShowMovieEditPage和MovieEdit这两个方法

 1 private dynamic ShowMovieEditPage(int movieId) 2     { 3       string getOneMovieStoredProcedure = @"up_GetMovieByMovieId"; 4       string getALLTypeStoredProcedure = @"up_GetAllMovieTypes"; 5       DynamicParameters dynamicParameters = new DynamicParameters(); 6       dynamicParameters.Add("@MovieId", movieId); 7  8       using (IDbConnection conn = OpenConnection()) 9       {10         var movieViewModel = conn.Query<MovieViewModel>(getOneMovieStoredProcedure, dynamicParameters, null, true, null, CommandType.StoredProcedure).SingleOrDefault();11         ViewBag.typeList = conn.Query<MovieType>(getALLTypeStoredProcedure, null, null, true, null, CommandType.StoredProcedure);12         return View["Edit", movieViewModel];13         14       }15     }

ShowMovieEditPage
 1   private dynamic MovieEdit(Movie movie) 2     { 3       string updateMovieStoredProcedure = @"up_UpdateMovieByMovieId"; 4       DynamicParameters dynamicParameters = new DynamicParameters(); 5       dynamicParameters.Add("@MovieId", movie.MovieId); 6       dynamicParameters.Add("@MovieName", movie.MovieName); 7       dynamicParameters.Add("@MovieTypeId", movie.MovieTypeId); 8  9       using (IDbConnection conn = OpenConnection())10       {11         conn.Execute(updateMovieStoredProcedure, dynamicParameters, null, null, CommandType.StoredProcedure);12         return Response.AsRedirect("/movie");13       }14     }

MovieEdit

添加一个Movie的Edit视图

 1 @inherits Nancy.ViewEngines.Razor.NancyRazorViewBase<MovieDemo.ViewModels.MovieViewModel> 2 @{ 3   ViewBag.Title = "修改电影信息"; 4   Layout = "Views/_Layout.cshtml"; 5 } 6  7 <form action="[email protected]" method="post"> 8   <div class="form-group"> 9     <label class="control-label col-md-2">电影名称</label>10     <div class="col-md-10">11       <input type="text" class="form-control" id="MovieName" name="MovieName" value="@Model.MovieName" />12     </div>13   </div>14   <div class="form-group">15     <label class="control-label col-md-2">电影类型</label>16     <div class="col-md-10">17       <select id="MovieTypeId" name="MovieTypeId" class="form-control">18         @foreach (var item in (System.Collections.Generic.List<MovieDemo.Models.MovieType>)ViewBag.typeList)19         {20           if (Model.MovieTypeId == item.TypeId)21           {22             <option selected="selected" value="@item.TypeId">@item.TypeName</option>23           }24           else25           {26             <option value="@item.TypeId">@item.TypeName</option>27           }28         }29 30       </select>31     </div>32   </div>33   <div class="form-group">34     <div class="col-md-offset-2 col-md-10">35       <input type="submit" value="修改" class="btn btn-default" />36     </div>37   </div>38 </form>

Edit.cshtml

然后即可跑起来了。

其中用到了一个模型绑定,需要添加Nancy.ModelBinding引用,有了这个绑定,省了很多事!!

 var movie = this.Bind<Movie>();

同理,增加和删除也是同样的做法,下面是MovieModule.cs的完整代码

 1 using MovieDemo.Models; 2 using MovieDemo.ViewModels; 3 using Dapper; 4 using Nancy; 5 using Nancy.ModelBinding; 6 using System.Data; 7 using System.Data.SqlClient; 8 using System.Linq; 9  10 namespace MovieDemo.Modules 11 { 12   public class MovieModule : NancyModule 13   { 14     public MovieModule() : base("/movie") 15     { 16       Get["/"] = _ => ShowMovieIndexPage(); 17  18       Get["/edit/{movieId}"] = _ => ShowMovieEditPage(_.movieId); 19       Post["/edit/{movieId}"] = _ => 20       { 21         var movie = this.Bind<Movie>(); 22         return MovieEdit(movie); 23       }; 24  25       Get["/create"] = _ => ShowMovieCreatePage(); 26       Post["/create"] = _ => 27       { 28         var movie = this.Bind<Movie>(); 29         return MovieCreate(movie); 30       }; 31  32       Get["/delete/{movieId}"] = _ => MovieDelete(_.movieId); 33     } 34  35     private readonly string _sqlconnection = 36         "Data Source=192.168.0.71;Initial Catalog=NancyDemo;User Id=sa;Password=dream_time1314;"; 37  38     public SqlConnection OpenConnection() 39     { 40       SqlConnection connection = new SqlConnection(_sqlconnection); 41       connection.Open(); 42       return connection; 43     } 44  45     private dynamic MovieDelete(int movieId) 46     { 47       string deleteMovieStoredProcedure = @"up_DeleteMovieByMovieId"; 48       DynamicParameters dynamicParameters = new DynamicParameters(); 49       dynamicParameters.Add("@MovieId", movieId); 50       using (IDbConnection conn = OpenConnection()) 51       { 52         conn.Execute(deleteMovieStoredProcedure, dynamicParameters, null, null, CommandType.StoredProcedure); 53         return Response.AsRedirect("/movie"); 54       } 55     } 56  57     private dynamic MovieCreate(Movie movie) 58     { 59       string createMovieStoredProcedure = @"up_InsertMovie"; 60       DynamicParameters dynamicParameters = new DynamicParameters(); 61       dynamicParameters.Add("@MovieName", movie.MovieName); 62       dynamicParameters.Add("@MovieTypeId", movie.MovieTypeId); 63       dynamicParameters.Add("@MovieAddTime", movie.MovieAddTime); 64  65       using (IDbConnection conn = OpenConnection()) 66       { 67         conn.Execute(createMovieStoredProcedure, dynamicParameters, null, null, CommandType.StoredProcedure); 68         return Response.AsRedirect("/movie"); 69       } 70     } 71  72     private dynamic ShowMovieCreatePage() 73     { 74       string getALLTypeStoredProcedure = @"up_GetAllMovieTypes"; 75       using (IDbConnection conn = OpenConnection()) 76       { 77         MovieTypeListViewModel viewModel = new MovieTypeListViewModel 78         { 79           MovieTypes = conn.Query<MovieType>(getALLTypeStoredProcedure, null, null, true, null, CommandType.StoredProcedure) 80         }; 81         return View["Create", viewModel]; 82       } 83     } 84  85     private dynamic MovieEdit(Movie movie) 86     { 87       string updateMovieStoredProcedure = @"up_UpdateMovieByMovieId"; 88       DynamicParameters dynamicParameters = new DynamicParameters(); 89       dynamicParameters.Add("@MovieId", movie.MovieId); 90       dynamicParameters.Add("@MovieName", movie.MovieName); 91       dynamicParameters.Add("@MovieTypeId", movie.MovieTypeId); 92  93       using (IDbConnection conn = OpenConnection()) 94       { 95         conn.Execute(updateMovieStoredProcedure, dynamicParameters, null, null, CommandType.StoredProcedure); 96         return Response.AsRedirect("/movie"); 97       } 98     } 99 100     private dynamic ShowMovieEditPage(int movieId)101     {102       string getOneMovieStoredProcedure = @"up_GetMovieByMovieId";103       string getALLTypeStoredProcedure = @"up_GetAllMovieTypes";104       DynamicParameters dynamicParameters = new DynamicParameters();105       dynamicParameters.Add("@MovieId", movieId);106 107       using (IDbConnection conn = OpenConnection())108       {109         var movieViewModel = conn.Query<MovieViewModel>(getOneMovieStoredProcedure, dynamicParameters, null, true, null, CommandType.StoredProcedure).SingleOrDefault();110         ViewBag.typeList = conn.Query<MovieType>(getALLTypeStoredProcedure, null, null, true, null, CommandType.StoredProcedure);111         return View["Edit", movieViewModel];112         113       }114     }115 116     private dynamic ShowMovieIndexPage()117     {118       using (IDbConnection conn = OpenConnection())119       {120         string getAllMoviesStoredProcedure = @"up_GetAllMovies";121         MovieListViewModel viewModel = new MovieListViewModel122         {123           Movies = conn.Query<MovieViewModel>(getAllMoviesStoredProcedure,124           null, null, true, null, CommandType.StoredProcedure)125         };126         return View["Index", viewModel];127       }128     }129   }130 }

MovieModule.cs

 在添加相应的视图即可完成。

十一、下面还需要简单讲一下Bootstrapper

这个东西可以简单认为是引导程序,你可以自定义一些鬼东西,把它当作一个容器来用,

还可以通过它来实现依赖注入,里面有个默认的 TinyIoC 。。。。。详细介绍请看https://github.com/NancyFx/Nancy/wiki/Bootstrapper

下面是我的CustomBootstrapper.cs配置

 1 public class CustomBootstrapper : DefaultNancyBootstrapper 2   { 3     protected override void ConfigureApplicationContainer(TinyIoCContainer container) 4     { 5       base.ConfigureApplicationContainer(container); 6       //container.Register<IMoviesRepository, MoviesRepository>(); 7       //container.Register<IMovieTypesRepository, MovieTypesRepository>();     8     } 9     protected override void ConfigureConventions(NancyConventions nancyConventions)10     {11       base.ConfigureConventions(nancyConventions);12       nancyConventions.StaticContentsConventions.Add(StaticContentConventionBuilder.AddDirectory("Scripts"));13       nancyConventions.StaticContentsConventions.Add(StaticContentConventionBuilder.AddDirectory("Content"));14     }15   }

CustomBootstrapper.cs

依赖注入我是没有用的,所以我注释了。用过Ninject、Autofac、Unity这些的,相信依赖注入这一块理解起来So easy!

Nancy也有相应的拓展

https://github.com/NancyFx/Nancy.Bootstrappers.Autofac

https://github.com/NancyFx/Nancy.Bootstrappers.Unity

https://github.com/NancyFx/Nancy.Bootstrappers.Ninject

还有一块是ConfigureConventions

这一块似乎是用来处理静态文件(css、js)的,跟Mvc中的BundleConfig很类似

到这里,开发工作已经完成。下面是部署的时候了。

十二、将做的MovieDemo部署到Linux下

Linux环境及配置

CentOS 6.7  + mono 4.2.2 + Jexus 5.8.0

将发布过后的目录上传到centos的 /var/www/ 中,然后在 /usr/jexus/siteconf 中建立一个新的配置文件

重新启动jexus即可。

下面上几张运行的图

完全的无缝兼容。

本篇的完整代码已托管到GitHub

 下载地址:https://github.com/hwqdt/Demos/tree/master/NancyDemoWithHostingAspnet

下雨天,心情压抑,写篇bolg来拯救自己的好心情 ~_~

后面有时间会写基于owin的demo