nopcommerce笔记2 - DependencyResolver.SetResolver

有时我们需要故意用错误来求得真相。

有一个控制器如下:

public class HomeController : Controller
{
//
// GET: /Home/

public HomeController(int i)
{
}

public ActionResult Index()
{
return View();
}

}

屏蔽了无参数的构造函数,在Application_Start中同时屏蔽NopDependencyResolver:

protected void Application_Start()
{
EngineContext.Initialize(false);
//set dependency resolver
var dependencyResolver = new NopDependencyResolver();
//DependencyResolver.SetResolver(dependencyResolver);

AreaRegistration.RegisterAllAreas();

WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
}

访问这个action,错误是:

 放开NopDependencyResolver,错误是:

可以看到屏蔽NopDependencyResolver时,交给

System.Activator.CreateInstance
去创建控制器实例

放开时,交给

Nop.Web.Framework.Mvc.NopDependencyResolver.GetService
去创建控制器实例

通过对错误提示的分析,放开NopDependencyResolver时,纠结在参数不能解析,于是想到给控制器构造函数参数给默认值,果然就通过了,不再有错误。

public class HomeController : Controller
{
//
// GET: /Home/

public HomeController(int i=1)
{
}

public ActionResult Index()
{
return View();
}

}

 

切换成屏蔽NopDependencyResolver时,错误依然。

然后,还有然后,在网上,根据这个网址:

http://www.nopchina.com/forum.php?mod=viewthread&tid=109

又思考了一下,既然是ioc,那么去掉默认值,把int的实例注册进去应该是可以的,也就是这样:

去掉默认值:

public class HomeController : Controller
{
//
// GET: /Home/

public HomeController(int i)
{
}

public ActionResult Index()
{
return View();
}

}

注册一个int 单例:

public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
EngineContext.Initialize(false);
//set dependency resolver
var dependencyResolver = new NopDependencyResolver();
DependencyResolver.SetResolver(dependencyResolver);

AreaRegistration.RegisterAllAreas();

WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);

EngineContext.Current.ContainerManager.AddComponentInstance<int>(100, "forhome", Nop.Core.Infrastructure.DependencyManagement.ComponentLifeStyle.Singleton);
}
}

结果是没有错误。

同时好像发现对int这种注册,必须是ComponentLifeStyle.Singleton,改成ComponentLifeStyle.Transient报错如下:

可以看见很多流程性的东西,至于100为什么必须是单例,也许可以纠结下去,但我还是打住。上面的图贴出来,就是为了看看调用Application_Start的流程而已。

然后想到,我注册多个int,效果是怎样的?

于是:

控制器:

public class HomeController : Controller
{
//
// GET: /Home/
private int n;

public HomeController(int i)
{
n = i;
}

public ActionResult Index()
{
ViewBag.n = n;
return View();
}

}

view:

@{
ViewBag.Title = "Index";
}

<h2>@ViewBag.n</h2>

 Application_Start:

protected void Application_Start()
{
EngineContext.Initialize(false);
//set dependency resolver
var dependencyResolver = new NopDependencyResolver();
DependencyResolver.SetResolver(dependencyResolver);

AreaRegistration.RegisterAllAreas();

WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);

EngineContext.Current.ContainerManager.AddComponentInstance<int>(100, "forhome1", Nop.Core.Infrastructure.DependencyManagement.ComponentLifeStyle.Singleton);


EngineContext.Current.ContainerManager.AddComponentInstance<int>(999, "forhome2", Nop.Core.Infrastructure.DependencyManagement.ComponentLifeStyle.Singleton);


EngineContext.Current.ContainerManager.AddComponentInstance<int>(777, "forhome3", Nop.Core.Infrastructure.DependencyManagement.ComponentLifeStyle.Singleton);
}

我猜是777,结果是它。

然后,又想到是否可以在:

protected void Application_BeginRequest(object sender, EventArgs e)
{
EngineContext.Current.ContainerManager.AddComponentInstance<HomeController>(new HomeController(2000), "ddd", Nop.Core.Infrastructure.DependencyManagement.ComponentLifeStyle.Singleton);
}

 

果然是2000,只是和上面一样,为什么必须ComponentLifeStyle.Singleton。

不是话:

为什么必须是单例?

回家后又仔细思考,首先我想清楚了为什么必须是ComponentLifeStyle.Singleton。因为AddComponentInstance注册进ioc容器中的本身就是一个实例,不是容器创建出来的,这样的实例,容器是不应该(不是不能)管理它的生命周期的。

想要一个临时的实例,应该使用注册基类(或接口)和实现类的方法,这样容器依据实现类创建的实例才可以指定为单例或者临时,这种创建出的实例显然只有通过容器才能拿到,因此它的生命周期完全由容器控制是合理的。

例子如下:

protected void Application_BeginRequest(object sender, EventArgs e)
{
EngineContext.Current.ContainerManager.AddComponentInstance<int>(2400, "p1");
Dictionary<string,string> p = new Dictionary<string,string>();
p.Add("i", "p1");// i是HomeController构造函数参数名

EngineContext.Current.ContainerManager.AddComponentWithParameters<Controller, HomeController>(p, "kkk", ComponentLifeStyle.Transient);

}

结果是2400。

protected void Application_BeginRequest(object sender, EventArgs e)
{
EngineContext.Current.ContainerManager.AddComponentInstance<int>(2500, "p1");

EngineContext.Current.ContainerManager.AddComponent<Controller, HomeController>( "kkk", ComponentLifeStyle.Transient);

}

是2500。

其实下面一句是多余的,改成如下也是可以的:

protected void Application_BeginRequest(object sender, EventArgs e)
{

EngineContext.Current.ContainerManager.AddComponentInstance<int>(2500, "p1");

}

 

还有一个很重要的发现:

NopDependencyResolver 与

Presentation\Nop.Web.Framework\DependencyRegistrar.cs

中的这个注册是息息相关的:

//controllers
builder.RegisterControllers(typeFinder.GetAssemblies().ToArray());

如果不注册,会使用默认方式生成控制器

 

我写这么多,觉得收获主要有:

1、DependencyResolver.SetResolver :让我们有了干涉Controller实例生成的钩子,还可干涉别的啥,暂时不知道

2、NopDependencyResolver :让我们可以在Autofac的ioc容器中去发挥对Controller的生成控制

3、进一步理解了ioc

posted on 2013-11-07 15:48  whwqs  阅读(819)  评论(0编辑  收藏  举报

导航