我有一个公共站点控制器,我的所有控制器都来自我的MVC网站。我已将公共服务类放在那里的所有视图/控制器中。
public class SiteController : Controller {
#region Properties
public IGlobalService GlobalService { get; set; }
public IMenuService MenuService { get; set; }
public IClientService ClientService { get; set; }
public ICertificateService CertificateService { get; set; }
#endregion
protected override void OnActionExecuting( ActionExecutingContext filterContext ) {
ViewBag.ErrorEmail = GlobalService.ErrorEmail;
ViewBag.Company = GlobalService.Company;
ViewBag.TopLevel = MenuService.GetTopLevel();
base.OnActionExecuting( filterContext );
}
最近,我开始实现一个动态菜单,并为Menu partial实现了一个ChildActionOnly方法
[ChildActionOnly]
public ActionResult Menu() {
var items = MenuService.GetTopLevel();
if( items == null || items.Count > 0 )
throw new NullReferenceException("Menu must have at least 1 top-level Menu Item!");
var topmenu = new Menu();
foreach( var item in items ) {
topmenu.Items.Add( new MenuItem( item.MenuId ){
MenuItemName = item.Key,
MenuItemPath = item.Value
});
}
return PartialView("_Menu", topmenu);
}
直到我实现了ChildActionOnly方法,理论上正在注入MenuService对象。我无法验证这一点,因为在我开始调试ViewBag.TopLevel = MenuService.GetTopLevel();
之前它没有被使用。
话虽如此,当我将断点放在ViewBag.TopLevel
的行上时,我可以检查与Controller关联的4个Service属性中的3个。如上所述,MenuService
属性是唯一未初始化的属性。
这是我的WindsorContainer
初始化程序:
public static void Initialize(string log4netPath) {
var container = new WindsorContainer();
container.Kernel.ComponentModelCreated += ( s => {
if( s.LifestyleType == LifestyleType.Undefined )
s.LifestyleType = LifestyleType.PerWebRequest;
} );
container.Install(
new DomainInstaller(),
new RepositoryInstaller() ,
new ServiceInstaller() ,
FromAssembly.This()
);
ControllerBuilder.Current.SetControllerFactory(new WindsorControllerFactory( container.Kernel ) );
container.AddFacility( new LoggingFacility( LoggerImplementation.Log4net , log4netPath ) );
CWC.Init( container );
}
ServiceInstaller
声明:
public class ServiceInstaller : IWindsorInstaller {
#region IWindsorInstaller Members
public void Install( Castle.Windsor.IWindsorContainer container , Castle.MicroKernel.SubSystems.Configuration.IConfigurationStore store ) {
container.Register( Types.FromAssembly( Assembly.GetExecutingAssembly() )
.Where( t => t.Namespace.StartsWith( "Woodsoft.Service" ) )
.WithService.FirstInterface().LifestylePerWebRequest() );
}
#endregion
}
MenuService
声明:
public interface IMenuService {
ICollection<Menu> GetTopLevel();
ICollection<Menu> GetChildren( int id );
}
public class MenuService : IMenuService {
public IMenuRepository MenuRepository { get; set; }
public MenuService() { }
public ICollection<Menu> GetTopLevel() {
return MenuRepository.FindAll()
.Where( m => ( m.ParentId == null || m.ParentId == 0 ) )
.ToList();
}
public ICollection<Menu> GetChildren( int id ) {
return MenuRepository.FindChildren( id );
}
}
也许有一些我缺少的东西,但是如果4个Service对象中的3个正在初始化并且在调试时可以访问,那么会发生什么会导致1个Service对象没有初始化,并且通过代理不可用。
为了比较,这里是GlobalService
对象:
public interface IGlobalService {
string this[ string key ] { get; set; }
string AdminEmail { get; set; }
string BCCEmail { get; set; }
string ErrorEmail { get; set; }
string Domain { get; set; }
string Company { get; set; }
}
public class GlobalService : IGlobalService {
public IGlobalRepository GlobalRepository { get; set; }
public GlobalService() { }
#region Getter/Setter methods
public string GetValue( string key ) {
return GlobalRepository.FindByKey( key ).Value;
}
private void SetValue( string key , string value ) {
var global = GlobalRepository.FindByKey( key );
global.Value = value;
GlobalRepository.Save();
}
#endregion
#region IGlobalService Members
public string this[ string key ] {
get { return GetValue( key ); }
set { SetValue( key , value ); }
}
public string AdminEmail {
get { return this[ "admin_email" ].ToEmail( Domain ); }
set { this[ "admin_email" ] = value; }
}
public string BCCEmail {
get { return this[ "bcc_email" ].ToEmail( Domain ); }
set { this[ "bcc_email" ] = value; }
}
public string ErrorEmail {
get { return this[ "error_email" ].ToEmail( Domain ); }
set { this[ "error_email" ] = value; }
}
public string Domain {
get { return this[ "domain" ]; }
set { this[ "domain" ] = value; }
}
public string Company {
get { return this[ "company" ]; }
set { this[ "company" ] = value; }
}
#endregion
}
我将它从IMenuService
更改为IMenuRepository
并且它加载了接口就好了。
虽然MenuService
内部的某些属性/方法存在潜在问题,但似乎没有。
以下是WindsorControllerFactory
:
public class WindsorControllerFactory : DefaultControllerFactory {
private readonly IKernel Kernel;
public WindsorControllerFactory( IKernel kernel ) {
Kernel = kernel;
}
public override void ReleaseController( IController controller ) {
Kernel.ReleaseComponent( controller );
}
protected override IController GetControllerInstance( System.Web.Routing.RequestContext requestContext , Type controllerType ) {
if( controllerType == null )
throw new HttpException( 404 , string.Format( "The controller for path '{0}' could not be found." , requestContext.HttpContext.Request.Path ) );
return ( IController ) Kernel.Resolve( controllerType );
}
}