[asp.net
mvc 小牛之路]05 - 使用 ninject
在[asp.net mvc 小牛之路]系列上一篇文章(依赖注入(di)和ninject)的末尾提到了在asp.net
mvc中使用ninject要做的两件事情,续这篇文章之后,本文将用一个实际的示例来演示ninject在asp.net mvc中的应用。
为了更好的理解和撑握本文内容,强烈建议初学者阅读本文前先阅读依赖注入(di)和ninject。
本文目录:
准备工作
新建一个名为bookshop的空白解决方案。在该解决方案中分别添加一个名为bookshop.webui的mvc空应用程序,和一个名为bookshop.domain的类库工程。目录结构如下:
两个工程添加完后,在bookshop.webui工程下添加bookshop.domain工程的引用。
使用nuget分别为bookshop.webui工程和bookshop.domain工程安装ninject包(nuget的介绍请阅读依赖注入(di)和ninject)。可以通过可视化窗口安装,也可以打开package
manager console(视图->其他窗口->package manager console)执行下面命令安装:
install-package ninject -project bookshop.webui
install-package ninject -project bookshop.domain
下图说明安装成功:
创建controller factory
我们知道,在asp.net mvc中,一个客户端请求是在特定controller的action中进行处理的。 默认情况下,asp.net mvc使用内置的controller工厂类 defaultcontrollerfactory来创建某个请求对应的controller实例。有时候默认的controller工厂不能满足我们实际的需求,我们就需要对这种默认行为进行扩展,即创建一个继承自defaultcontrollerfactory类的自定义controller工厂类并重写其中的一些方法。为此,我们在bookshop.webui工程下创建一个名为infrastructure的文件夹,在该文件夹中添加一个名为ninjectcontrollerfactory的工厂类,代码如下:
public class ninjectcontrollerfactory : defaultcontrollerfactory {
private ikernel ninjectkernel;
public ninjectcontrollerfactory() {
ninjectkernel = new standardkernel();
addbindings();
}
protected override icontroller getcontrollerinstance(requestcontext requestcontext, type controllertype) {
return controllertype == null ? null : (icontroller)ninjectkernel.get(controllertype);
}
private void addbindings() {
// todo:后面再来添加绑定
}
}
上面代码中的 ninjectkernel.get(controllertype) 可获取到一个controller实例。在这里如果手动实例化controller类是一个非常复杂的过程,我们不知道controller类有没有带参数的构造函数,也不知道构造函数的参数是什么类型。而使用ninject只需要使用上面的一个get方法就可以,ninject内部会自动处理所有的依赖关系,智能地创建我们需要的对象。
controller工厂类创建好后,我们就需要告诉mvc用我们的ninjectcontrollerfactory类来创建controller对象,为此,需在global.asax文件的application_start方法中添加下面代码:
protected void application_start() {
......
//设置controller工厂
controllerbuilder.current.setcontrollerfactory(new ninjectcontrollerfactory());
}
这里我们暂且不去关心上面这段代码是什么原理,知道设置自定义的controller工厂必须要在这注册就行了,有空的话我会在后续博文对这部分内容进行更深入的讲解。
添加domain model
在mvc应用程序中,一切都是围绕domain model(领域模型)来的。 所以我们在bookshop.domain工程中专门建一个名为entities的文件夹,用来存放领域实体模型。作为一个电子商务类的网上书店,当然最重要的一个领域实体就是book了。由于只是为了演示,我们简单定义一个book类,并在entities文件夹中添加该类,代码如下:
public class book {
public int id { get; set; }
public string title { get; set; }
public string isbn { get; set; }
public string summary { get; set; }
public string author { get; set; }
public byte[] thumbnail { get; set; }
public decimal price { get; set; }
public datetime published { get; set; }
}
添加repository
我们知道,我们肯定需要一种方式来从数据库中读取book数据。在这我们不防为数据的使用者(这里指controller)提供一个ibookrepository接口,在这个接口中声明一个iqueryable<book>类型的属性books。这样,通过该接口使用依赖注入,使用者就可以拿到books数据集合,而不用关心数据是如何得到的。为此,我们在bookshop.domain工程中添加一个名为 abstract的文件夹,在该文件夹中添加我们的ibookrepository接口文件,代码如下:
public interface ibookrepository {
iqueryable<book> books { get; }
}
在mvc中我们一般会用仓储模式(repository pattern)把数据相关的逻辑和领域实体模型分离,这样对于使用者来说,通过调用仓储对象,使用者可以直接拿到自己想要的数据,而完全不必关心数据具体是如何来的。我们可以把仓储比喻成一个超市,超市已经为消费者供备好了商品,消费者只管去超市选购自己需要的商品,而完全不必关心这些商品是从哪些供应商怎么样运输到超市的。但对于仓储本身,必须要实现读取数据的“渠道”。
在bookshop.domain工程中添加一个名为concrete文件夹用于存放具体的类。我们在concrete文件夹中添加一个实现了ibookrepository接口的bookrepository类来作为我们的book数据仓储。bookrepository类代码如下:
public class bookrepository : ibookrepository {
public iqueryable<book> books {
get { return getbooks().asqueryable(); }
}
private static list<book> getbooks() {
//为了演示,这里手工造一些数据,后面会介绍使用ef从数据库中读取。
list<book> books = new list<book>{
new book { id = 1, title = "asp.net mvc 4 编程", price = 52},
new book { id = 2, title = "clr via c#", price = 46},
new book { id = 3, title = "平凡的世界", price = 37}
};
return books;
}
}
为了演示,上面是手工造的一些数据,后面的文章我将介绍使用entity framwork从数据库中读取数据。对于刚接触orm框架的朋友可能对这里iqueryable感到奇怪,为什么用iqueryable作为返回类型,而不用ienumerable呢?后面有机会讲entity framwork的时候再讲。
添加绑定
打开之前我们在bookshop.webui工程创建的ninjectcontrollerfactory类,在addbindings方法中添加如下代码
private void addbindings() {
ninjectkernel.bind<ibookrepository>().to<bookrepository>();
}
这句代码,通过ninject把ibookrepository接口绑定到bookrepository,当ibookrepository接口的实现被请求时,ninject将自动创建bookrepository类的实例。
到这里,ninject的使用步骤就结束了,接下来我们把本示例剩余的步骤完成。
显示列表
右击bookshop.webui工程的controllers文件夹,添加一个名为book的controller,按下面代码对其进行编辑:
public class bookcontroller : controller {
private ibookrepository repository;
public bookcontroller(ibookrepository bookrepository) {
repository = bookrepository;
}
}
在这,bookcontroller的构造函数接受了一个ibookrepository参数,当bookcontroller被实例化的时候,ninject就为其注入了bookrepository的依赖。接下来我们为这个controller添加一个名为list的action,用来呈现book列表。代码如下:
public class bookcontroller : controller {
...
public viewresult list() {
return view(repository.books);
}
}
当然我们需要添加一个view。右击上面的list方法,选择添加视图,在弹出的窗口进行如下配置:
然后我们在list.cshtml中用foreach循环来列举书本信息,代码如下:
@model ienumerable<bookshop.domain.entities.book>
@{
viewbag.title = "books";
}
@foreach (var p in model) {
<div class="item" style="border-bottom:1px dashed silver;">
<h3>@p.title</h3>
<p>价格:@p.price.tostring("c") </p>
</div>
}
最后我们还需要修改一下默认路由,让系统运行后直接导向到我们的{controller = "book", action = "list"},打开global.asax文件,找到registerroutes方法,进行如下修改:
public static void registerroutes(routecollection routes) {
routes.ignoreroute("{resource}.axd/{*pathinfo}");
routes.maproute(
"default", // route name
"{controller}/{action}/{id}", // url with parameters
new { controller = "book", action = "list", id = urlparameter.optional }
);
}
到这,我们的程序可以运行了,效果如下:
结束语:
本文是ninject在asp.net mvc中使用的一个简单示例,目的是让大家了解ninject在mvc中的使用方法。当然,ninject的强大之处不仅限于本文所演示的,相信当你熟悉了niject之后,在搭建mvc应用程序时,你一定会喜欢上它的。
以上就是[asp.net mvc 小牛之路]05 - 使用 ninject的内容。
