Self Host 使得Nancy 能够在任意application 中启动,无论是console 还是windows service。这期我们使用的版本是Nancy v0.4.0。

Demo

首先看一下使用方式:

class Program
{
static void Main(string[] args)
{
var nancyHost = new NancyHost(new Uri("http://localhost:8888/nancy/"));
nancyHost.Start();
Console.WriteLine("Nancy now listening - navigate to http://localhost:8888/nancy/. Press enter to stop");
Console.ReadKey();
nancyHost.Stop();
Console.WriteLine("Stopped. Good bye!");
}
}

这是一个控制台的例子,我们在Main方法中直接创建一个NancyHost的实例,然后调用nancyHost.Start()。warning: 当前版本的实现为早期版本,仅仅是为了演示而使用,请勿deploy在生产环境中。

   public NancyHost(Uri baseUri, INancyBootstrapper bootStrapper)
{
this.baseUri = baseUri;
listener = new HttpListener();
listener.Prefixes.Add(baseUri.ToString()); bootStrapper.Initialise();
engine = bootStrapper.GetEngine();
}

NancyHost 需要两个参数,Uri,以及INancyBootstrapper。Uri这里我们传入的是new Uri("http://localhost:8888/nancy/"。INancyBootstrapper这个参数可以省略,Nancy 启动的时候会反射加载所有实现了INancyBootstrapper的启动器实现。INancyBootstrapper可以用来作依赖注入框架的启动器,实现该接口的类有:

可以看到除了测试用的fake实现,都是一些IOC框架(Ninject,StructureMap,Unity......)。NancyBootstrapperLocator类具体负责寻找实现了该接口的启动器,如果找不到,就会使用默认的TinyIoCContainer作为IOC 容器。

static NancyBootstrapperLocator()
{
// Get the first non-abstract implementation of INancyBootstrapper if one exists in the
// app domain. If none exist then just use the default one.
var bootstrapperInterface = typeof(INancyBootstrapper);
var defaultBootstrapper = typeof(DefaultNancyBootstrapper); var locatedBootstrappers = from assembly in AppDomain.CurrentDomain.GetAssemblies()
where !assembly.IsDynamic
from type in assembly.SafeGetExportedTypes()
where !type.IsAbstract
where bootstrapperInterface.IsAssignableFrom(type)
where type != defaultBootstrapper
select type; var bootstrapperType = locatedBootstrappers.FirstOrDefault() ?? defaultBootstrapper; Bootstrapper = (INancyBootstrapper) Activator.CreateInstance(bootstrapperType);
}

我们可以看到所有默认接口都指定了Default的实现。

private IEnumerable<TypeRegistration> BuildDefaults()
{
return new[]
{
new TypeRegistration(typeof(IRouteResolver), DefaultRouteResolver),
new TypeRegistration(typeof(INancyEngine), DefaultNancyEngine),
new TypeRegistration(typeof(IModuleKeyGenerator), DefaultModuleKeyGenerator),
new TypeRegistration(typeof(IRouteCache), DefaultRouteCache),
new TypeRegistration(typeof(IRouteCacheProvider), DefaultRouteCacheProvider),
new TypeRegistration(typeof(IRoutePatternMatcher), DefaultRoutePatternMatcher),
new TypeRegistration(typeof(IViewLocator), DefaultViewLocator),
new TypeRegistration(typeof(IViewFactory), DefaultViewFactory),
new TypeRegistration(typeof(INancyContextFactory), DefaultContextFactory),
new TypeRegistration(typeof(INancyModuleBuilder), DefaultNancyModuleBuilder),
new TypeRegistration(typeof(IResponseFormatter), DefaultResponseFormatter)
};
}

Nancy 面向接口编程做的比较的不错。接下去,我们继续完成NancyHost的初始化,这里创建一个HttpListener的实例。HttpListener是System.dll中提供的一个类:

  /// <summary>
/// Provides a simple, programmatically controlled HTTP protocol listener. This class cannot be inherited.
/// </summary>
public sealed class HttpListener : IDisposable

有了这个类就方便了很多,我们不需要自己去处理socket。接下去我们启动NancyHost。

    public void Start()
{
shouldContinue = true; listener.Start();
thread = new Thread(Listen);
thread.Start();
}

这里就是这个简易版本的问题所在了,程序只是启动了一个线程去处理所有的http请求。在线程中,将所有的context,request作了一轮适配器一样的转换,最终将NancyResponse转变会HttpListener需要的Response。不过虽然同样是一个死循环的写法,while (shouldContinue)的做法明显是优于while(true)的,无则加勉,大家要有这个意识。

改进Self Host

单线程阻塞当然不妥当,不过这样就基本实现了一个简易的Self Host。接下去,让我们把视野切换到版本1.4.1。

   private void StartListener()
{
if (this.TryStartListener())
{
return;
} if (!this.configuration.UrlReservations.CreateAutomatically)
{
throw new AutomaticUrlReservationCreationFailureException(this.GetPrefixes(), this.GetUser());
} if (!this.TryAddUrlReservations())
{
throw new InvalidOperationException("Unable to configure namespace reservation");
} if (!TryStartListener())
{
throw new InvalidOperationException("Unable to start listener");
}
}
}

同样是HttpListener,这里的启动更加的成熟,增加了不少错误处理的判断。

    public void Start()
{
this.StartListener(); try
{
this.listener.BeginGetContext(this.GotCallback, null);
}
catch (Exception e)
{
this.configuration.UnhandledExceptionCallback.Invoke(e); throw;
}
}

在启动完HttpListener后,这里最大的不同是使用异步回调的方式,不再是单线程阻塞模式。

private void GotCallback(IAsyncResult ar)
{
try
{
var ctx = this.listener.EndGetContext(ar);
this.listener.BeginGetContext(this.GotCallback, null);
this.Process(ctx);
}
catch (Exception e)
{
this.configuration.UnhandledExceptionCallback.Invoke(e); try
{
this.listener.BeginGetContext(this.GotCallback, null);
}
catch
{
this.configuration.UnhandledExceptionCallback.Invoke(e);
}
}
}

采用标准的回调处理,每个请求将会在它自己的独立线程中执行。

private void Process(HttpListenerContext ctx)
{
try
{
var nancyRequest = this.ConvertRequestToNancyRequest(ctx.Request);
using (var nancyContext = this.engine.HandleRequest(nancyRequest))
{
try
{
ConvertNancyResponseToResponse(nancyContext.Response, ctx.Response);
}
catch (Exception e)
{
this.configuration.UnhandledExceptionCallback.Invoke(e);
}
}
}
catch (Exception e)
{
this.configuration.UnhandledExceptionCallback.Invoke(e);
}
}

至此,self host相关内容结束。

当当当当 - つづく

.NET Nancy 详解(四) Self Host的更多相关文章

  1. .NET DLL 保护措施详解(四)各操作系统运行情况

    我准备了WEB应用程序及WinForm应用程序,分别在WIN SERVER 2012/2008/2003.Win7/10上实测,以下为实测结果截图: 2012 2008 2003 WIN7 WIN10 ...

  2. logback -- 配置详解 -- 四 -- <filter>

    附: logback.xml实例 logback -- 配置详解 -- 一 -- <configuration>及子节点 logback -- 配置详解 -- 二 -- <appen ...

  3. pika详解(四) channel 通道

    pika详解(四) channel 通道   本文链接:https://blog.csdn.net/comprel/article/details/94662394 版权 ​ channel通道 通道 ...

  4. View绘制详解(四),谝一谝layout过程

    上篇博客我们介绍了View的测量过程,这只是View显示过程的第一步,第二步就是layout了,这个我们一般译作布局,其实就是在View测量完成之后根据View的大小,将其一个一个摆放在ViewGro ...

  5. tomcat 配置文件server.xml 详解 Connector Engine Host Context

    目录 一 server.xml 1.1 server 配置 1.2 service 配置 1.3 Executor 1.4 Connector 配置 1.5 Engine 其他tocmat 文章 一 ...

  6. C++11 并发指南六(atomic 类型详解四 C 风格原子操作介绍)

    前面三篇文章<C++11 并发指南六(atomic 类型详解一 atomic_flag 介绍)>.<C++11 并发指南六( <atomic> 类型详解二 std::at ...

  7. Android Studio 插件开发详解四:填坑

    转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/78265540 本文出自[赵彦军的博客] 在前面我介绍了插件开发的基本流程 [And ...

  8. webRTC中语音降噪模块ANS细节详解(四)

    上篇(webRTC中语音降噪模块ANS细节详解(三))讲了噪声的初始估计方法以及怎么算先验SNR和后验SNR. 本篇开始讲基于带噪语音和特征的语音和噪声的概率计算方法和噪声估计更新以及基于维纳滤波的降 ...

  9. Hadoop伪分布安装详解(四)

    目录: 1.修改主机名和用户名 2.配置静态IP地址 3.配置SSH无密码连接 4.安装JDK1.7 5.配置Hadoop 6.安装Mysql 7.安装Hive 8.安装Hbase 9.安装Sqoop ...

随机推荐

  1. 2. Android系统启动流程

    1.启动加载完内核 2.执行init进程   ----> 设备初始化工作       a1. 读取inic.rc       a2. 启动Zygote进程 ----> 该进程是所有进程的孵 ...

  2. ubuntu下配置apache2多域名(apache2.4.6)

    Ubuntu 在 Linux 各发行版中, 个人用户数量最多的. 很多人在本机和虚拟机中使用. 但 Ubuntu 和 Redhat 的 VirtualHost 设置方法不相同. 1. 打开目录 /et ...

  3. 【iOS开发-22】navigationBar导航条和navigationItem设置:基本搞定导航条上的文字和按钮以及各种跳转

    http://blog.csdn.net/weisubao/article/details/39646739?utm_source=tuicool&utm_medium=referral (1 ...

  4. 统计代码git提交的行数

    $ git log --author="$(git config --get user.name)" --pretty=tformat: --numstat | gawk '{ a ...

  5. jQuery之元素筛选

      1.eq()  筛选指定索引号的元素2.first() 筛选出第一个匹配的元素3.last() 筛选出最后一个匹配的元素4.hasClass() 检查匹配的元素是否含有指定的类5.filter() ...

  6. ASP.NET MVC Dropdownlist

    本文介绍如何在网页里显示DropDownList. Step 1: 在Control里面添加方法 public ActionResult ShowDropDownList() { return Vie ...

  7. Appium+Robotframework实现Android应用的自动化测试-7:模拟器频繁挂掉的解决方案

    如果测试用例比较多,则当持续运行多个测试用例后,经常会出现模拟器崩溃或者Appium无法连接到该模拟器的情况出现. 经过分析,本人认为这应该是模拟器或者Appium的缺陷造成的,目前并没有直接的解决方 ...

  8. 使用logrotate管理nginx日志文件

    本文转载自:http://linux008.blog.51cto.com/2837805/555829 描述:linux日志文件如果不定期清理,会填满整个磁盘.这样会很危险,因此日志管理是系统管理员日 ...

  9. java web 学习 --第六天(Java三级考试)

    第五天学习在这:http://www.cnblogs.com/tobecrazy/p/3458592.html session对象 当某个用户首次访问web应用系统时,jsp会自动创建出一个sessi ...

  10. MySQL进程常见的State【转】

    为了查阅方便,做个笔记. 通过show processlist查看MySQL的进程状态,在State列上面的状态有如下这些: Analyzing线程对MyISAM 表的统计信息做分析(例如, ANAL ...