如何获取Web API / Castle Windsor来识别控制器?

 Jerl 发布于 2023-02-06 10:39

我发现了为什么占位符“ Home Controller”在这里被调用

我在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()
         .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()
         .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();
        container.Register(Component.For().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()
         .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();
    container.Register(Component.For().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

基于示例这里通过峰会Dishpanhands,我注释掉的代码我在RepositoriesInstaller以及与此替代它:

container.Register(
  Component.For().ImplementedBy()
);

尽管在Mudville仍然没有喜悦

更新5

在此处使用Summit的代码[ 使用Castle Windsor的WebAPI中的依赖注入,我将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),new 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,这似乎很有帮助,尤其是ServiceInstaller:IWindsorInstaller方法。

现在,我看到IRepository具有与其他生活方式(LifestylePerWebRequest)不同的生活方式(LifestyleTransient)。

IRepository是我应该参考的东西(我不是,它无法解决),还是您自己的自定义接口,例如其余所有接口(IUserService,IAppService等)?

1 个回答
  • 好的,让我们分解一下。您说的是WindsorControllerFactory.GetControllerInstance中的值为空。我假设您的意思是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));
    

    所以这是您需要做的:

    设置您的WebApi路由,以便WebApi而不是MVC处理对您的API的调用。

    实现IHttpControllerActivator,并向WebApi注册新的实现。

    更新资料

    我已经掌握了您的资料来源,并解决了一些问题。我在https://github.com/bclayshannon/WebAPICastleWindsorExtravaganza/pull/1上创建了包含其修复程序的请求请求。请看一下有关我所更改内容的详细信息。以下是我所做更改的简要摘要:

    IDepartmentsRepository的Windsor注册重复,导致在启动过程中引发异常。

    我必须用对GlobalConfiguration.Configure的调用替换Global.asax.cs中的WebApiConfig.Register调用。以前我得到的是404(但这可能只是我的机器和您的机器之间的区别)。

    我删除了一些导致MVC框架处理WebApi路由的MapRoutes调用。

    另外,我将所有API控制器都移到api文件夹中,以使内容更易于理解,并且在DepartmentsController上使用了属性路由。一个示例调用是GET / api / Departments / Count。使用属性路由不是必需的,但是通常可以使用它来创建一个体面的API。

    我已经验证我现在可以发出以下请求并进入DepartmentsController:

    GET / api /部门/计数

    GET / api /部门?ID = 123&CountToFetch = 100

    2023-02-06 10:43 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有