我发现了为什么占位符“Home Controller”被称为here
我在RouteConfig.cs中注释掉了对HomeController的引用,并添加了一个我希望它调用的Controller:
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
//If get 404 error re: favicon, see http://docs.castleproject.org/(X(1)S(vv4c5o450lhlzb45p5wzrq45))/Windsor.Windsor-tutorial-part-two-plugging-Windsor-in.ashx or just uncomment the line below:
//routes.IgnoreRoute("{*favicon}", new { favicon = @"(.*/)?favicon.ico(/.*)?" });
//routes.MapRoute(
// name: "Default",
// url: "{controller}/{action}/{id}",
// defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
//);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "DepartmentsController", action = "GetCountOfDepartmentRecords", id = UrlParameter.Optional }
);
}
}
...但这在WindsorControllerFactory中为我提供了一个空值:
protected override IController GetControllerInstance(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);
}
...即使在DepartmentsController中确实存在GetCountOfDepartmentRecords()也是如此:
public int GetCountOfDepartmentRecords()
{
return _deptsRepository.Get();
}
那么,我在设置或配置方面还是缺少什么?
注意:我还尝试了RouteConfig条目,但没有“Controller”字样:
defaults: new { controller = "Departments", action = "GetCountOfDepartmentRecords", id = UrlParameter.Optional }
...但是没关系。
更新
这是我在WindsorDependencyResolver中具有的功能:
public class ApiControllersInstaller : IWindsorInstaller
{
public void Install(Castle.Windsor.IWindsorContainer container, Castle.MicroKernel.SubSystems.Configuration.IConfigurationStore store)
{
container.Register(Classes.FromThisAssembly()
.BasedOn<ApiController>()
.LifestylePerWebRequest());
}
}
...难道我做错了什么?
更新2
也许我的项目中有太多实现IWindsorInstaller的类?
&& ||,与此相关,我在太多地方/太多地方叫container.Register()?
我在三个地方调用了container.Register():
0)WindsorDependencyResolver.cs:
public class ApiControllersInstaller : IWindsorInstaller
{
public void Install(Castle.Windsor.IWindsorContainer container, Castle.MicroKernel.SubSystems.Configuration.IConfigurationStore store)
{
container.Register(Classes.FromThisAssembly()
.BasedOn<ApiController>()
.LifestylePerWebRequest());
}
}
1)SomethingProviderInstaller.cs:
public class SomethingProviderInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(Classes.FromThisAssembly()
.BasedOn(typeof(ISomethingProvider))
.WithServiceAllInterfaces());
container.AddFacility<TypedFactoryFacility>();
container.Register(Component.For<IMyFirstFactory>().AsFactory());
}
}
2)RepositoriesInstaller
public class RepositoriesInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(
Types.FromThisAssembly()
.Where(type => type.Name.EndsWith("Repository"))
.WithService.DefaultInterfaces()
.Configure(c => c.LifestylePerWebRequest()));
}
}
这是“太好了”吗?
更新3
我的看法是:
public class ApiControllersInstaller : IWindsorInstaller
{
public void Install(Castle.Windsor.IWindsorContainer container, Castle.MicroKernel.SubSystems.Configuration.IConfigurationStore store)
{
container.Register(Classes.FromThisAssembly()
.BasedOn<ApiController>()
.LifestylePerWebRequest());
}
}
...应该注册实现ApiController接口的所有内容;因此,应该安装DepartmentsController。
public class DepartmentsController : ApiController
(所有其他Controller都应该这样做,因为它们都实现了ApiController接口)。
而这个:
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(Classes.FromThisAssembly()
.BasedOn(typeof(ISomethingProvider))
.WithServiceAllInterfaces());
container.AddFacility<TypedFactoryFacility>();
container.Register(Component.For<IMyFirstFactory>().AsFactory());
}
...只会注册实现ISomethingProvider的单个类。
最后是这个:
container.Register(
Types.FromThisAssembly()
.Where(type => type.Name.EndsWith(“Controllers”))
.WithService.DefaultInterfaces()
.Configure(c => c.LifestylePerWebRequest()));
...将注册名为Controller的所有内容。
注意:我更换了:
.Where(type => type.Name.EndsWith("Repository"))
...以及上面的内容(存储库)。
我在它们中都设置了断点,它们都被击中,然后被击中,其顺序与上面显示的顺序相反。所以我不知道是否只允许一个对container.Register()的调用,或者为什么我得到一个空的Controller ...
更新4
基于Summit Dishpanhands的here示例,我注释掉了RepositoriesInstaller中的代码,并用以下代码替换了它:
container.Register(
Component.For<IDepartmentRepository>().ImplementedBy<DepartmentRepository>()
);
尽管在Mudville仍然没有喜悦
更新5
在此处使用Summit的代码[Dependency Injection in WebAPI with Castle Windsor,我从以下位置将Global.asax.cs中的代码更改为:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
GlobalConfiguration.Configure(WebApiConfig.Register);
BootstrapContainer();
}
private static void BootstrapContainer()
{
_container = new WindsorContainer().Install(FromAssembly.This());
var controllerFactory = new WindsorControllerFactory(_container.Kernel);
ControllerBuilder.Current.SetControllerFactory(controllerFactory);
GlobalConfiguration.Configuration.Services.Replace(
typeof(IHttpControllerActivator), new WindsorCompositionRoot(_container));
}
...对此:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
ConfigureWindsor(GlobalConfiguration.Configuration);
}
public static void ConfigureWindsor(HttpConfiguration configuration)
{
_container = new WindsorContainer();
_container.Install(FromAssembly.This());
_container.Kernel.Resolver.AddSubResolver(new CollectionResolver(_container.Kernel, true));
var dependencyResolver = new WindsorDependencyResolver(_container);
configuration.DependencyResolver = dependencyResolver;
}
...而且我似乎已经走得更远了。现在,我得到了一个浏览时间异常,而不是运行时异常,即HTTP错误403.14-禁止:
我真的需要搞砸国际空间站吗,还是有其他方法可以解决这个难题?
更新6
针对Kiran Challa:
当我将其更改为MapHttpRoute时,如下所示:
routes.MapHttpRoute(
name: "Departments",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Departments", action = "GetCountOfDepartmentRecords", id = UrlParameter.Optional }
);
...我得到了编译时错误“'System.Web.Routing.RouteCollection'不包含'MapHttpRoute'的定义,并且没有扩展方法'MapHttpRoute'接受类型为'System.Web.Routing.RouteCollection的第一个参数'可以找到...”
更新7
谢谢你的帮助,基兰。
我确实有一个WebApiConfig.cs,实际上它已经具有所有这些:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
name: "DefaultApiWithParameters",
routeTemplate: "api/{controller}/{ID}/{CountToFetch}"
//defaults: new { ID = RouteParameter.Optional, CountToFetch = RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
name: "DefaultApiWith3Parameters",
routeTemplate: "api/{controller}/{ID}/{packSize}/{CountToFetch}"
//defaults: new { ID = RouteParameter.Optional, packSize = RouteParameter.Optional, CountToFetch = RouteParameter.Optional }
);
}
}
...所以我想我应该只注释掉RouteConfig.cs中的内容;看来我档案太多了;好像我的衣柜里塞满了易燃物。
更新8
对于亚当·康纳利:
“我假设您的意思是controllerType为null。”
是。
“目前您拥有类似以下内容的地方:
var controllerFactory =新的WindsorControllerFactory(container.Kernel);
ControllerBuilder.Current.SetControllerFactory(controllerFactory);
您还需要执行以下操作(或者,如果您的项目仅使用WebApi,则执行以下操作):
GlobalConfiguration.Configuration.Services.Replace(
typeof(IHttpControllerActivator),
新的WindsorControllerActivator(container));“
实际上,我确实有两个:
private static void BootstrapContainer()
{
_container = new WindsorContainer().Install(FromAssembly.This());
var controllerFactory = new WindsorControllerFactory(_container.Kernel);
ControllerBuilder.Current.SetControllerFactory(controllerFactory);
GlobalConfiguration.Configuration.Services.Replace(
typeof(IHttpControllerActivator), new WindsorCompositionRoot(_container));
}
...但目前未调用BootstrapContainer(),因此均未调用。替代的是:
private static IWindsorContainer _container;
. . .
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
ConfigureWindsor(GlobalConfiguration.Configuration);
}
public static void ConfigureWindsor(HttpConfiguration configuration)
{
_container = new WindsorContainer();
_container.Install(FromAssembly.This());
_container.Kernel.Resolver.AddSubResolver(new CollectionResolver(_container.Kernel, true));
var dependencyResolver = new WindsorDependencyResolver(_container);
configuration.DependencyResolver = dependencyResolver;
}
更新9
Serdar,this似乎非常有用,尤其是ServiceInstaller:IWindsorInstaller方法。
现在,我看到IRepository具有与其他生活方式(LifestylePerWebRequest)不同的生活方式(LifestyleTransient)。
IRepository是我应该参考的东西(我不是,它无法解决),还是它是您自己的自定义接口,例如所有其他接口似乎都是(IUserService,IAppService等)?
最佳答案
好的,让我们分解一下。您说的是在WindsorControllerFactory.GetControllerInstance中获得null。我假设您的意思是controllerType为null。
这意味着您的问题与Windsor无关,因此,通过暂时忽略您的Windsor配置,您可以避免很多混乱。问题是您的WebApi路由设置不正确,因此WebApi无法根据您提供的路由找到合适的控制器。
就像Kiran所说的,看起来您实际上没有为WebApi映射任何路由,这可能是您的问题所在。
此外,WebApi不使用MVC使用的WindsorControllerFactory,您需要一个单独的类来实现IHttpControllerActivator(有关示例的链接,请参见上面的Serdar帖子)。
您当前所在的位置如下:
var controllerFactory = new WindsorControllerFactory(container.Kernel);
ControllerBuilder.Current.SetControllerFactory(controllerFactory);
您还需要执行以下操作(或者,如果您的项目仅使用WebApi,则执行以下操作):
GlobalConfiguration.Configuration.Services.Replace(
typeof (IHttpControllerActivator),
new WindsorControllerActivator(container));
所以这是您需要做的:
更新
我已经掌握了您的资料来源,并解决了一些问题。我在https://github.com/bclayshannon/WebAPICastleWindsorExtravaganza/pull/1中创建了包含其修复程序的请求请求。看一看,了解我所做更改的详细信息。以下是我所做更改的简要摘要:
此外,我将所有API控制器都移到api文件夹中,以使内容更易于理解,并且在DepartmentsController上使用了属性路由。一个示例调用是GET / api / Departments / Count。
使用属性路由不是必需的,但是通常可以使用它来创建一个体面的API。
我已验证自己现在可以发出以下请求并进入DepartmentsController:
关于routes - 如何获取Web API/CaSTLe Windsor来识别 Controller ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20960690/