找到了多种与控制器匹配的类型

Posted

技术标签:

【中文标题】找到了多种与控制器匹配的类型【英文标题】:Multiple types were found that match the controller 【发布时间】:2016-01-11 06:46:42 【问题描述】:

我正在尝试使用headerapi versioning,但在different folder structure 中,如下所示。

Controller folder 中有V1 子文件夹在CustomerController.cs

Controller folder 中有V2 子文件夹在CustomerController.cs

当我使用上面的URL 使用 api 版本时工作正常。

我的问题是当我使用header 尝试这种方法时,它给了我以下错误:

"Message": "发生错误。", "ExceptionMessage": “找到了与名为‘客户’的控制器匹配的多种类型。 如果服务此请求的路由会发生这种情况 ('api/controller/id') 找到了多个使用 名称相同但命名空间不同,这是不受支持的。\r\n\r\n 对“客户”的请求已找到以下匹配项 控制器:\r\nApiVersion.Controllers.V1.CustomerController\r\nApiVersion.Controllers.V2.CustomerController","ExceptionType":"System.InvalidOperationException","StackTrace":" 在 System.Web.Http.Dispatcher.DefaultHttpControllerSelector.SelectController(HttpRequestMessage 请求)\r\n 在 System.Web.Http.Dispatcher.HttpControllerDispatcher.d__1.MoveNext()"

WebApiConfig.cs

 public static void Register(HttpConfiguration config)
        
            config.MapHttpAttributeRoutes();
            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/controller/id",
                defaults: new  id = RouteParameter.Optional 
            );
        

CustomeControllerSelector.cs

        public override HttpControllerDescriptor SelectController(HttpRequestMessage request)
        
            var controllers = GetControllerMapping();
            var routeData = request.GetRouteData();
            var controllerName = routeData.Values["controller"].ToString();
            //HttpControllerDescriptor controllerDescriptor;

            var version = GetVersionFromAcceptHeaderVersion(request);
            var controllerKey = String.Format(CultureInfo.InvariantCulture, "0.1",
                        version, controllerName);


            //if (controllers.TryGetValue(controllerName, out controllerDescriptor))
            // 

            if (!string.IsNullOrEmpty(version))
            
                HttpControllerDescriptor versionedControllerDescriptor;
                if (controllers.TryGetValue(controllerKey, out versionedControllerDescriptor))
                
                    return versionedControllerDescriptor;
                
            
            return null;
        

          private string GetVersionFromAcceptHeaderVersion(HttpRequestMessage request)
        
            var acceptHeader = request.Headers.Accept;
            foreach (var mime in acceptHeader)
            
                if (mime.MediaType == "application/json" || mime.MediaType == "text/html")
                
                    var version = mime.Parameters
                                    .Where(v => v.Name.Equals("version", StringComparison.OrdinalIgnoreCase))
                                    .FirstOrDefault();
                    if (version != null)
                    
                        return version.Value;
                    
                    return string.Empty;
                
            
            return string.Empty;
        

【问题讨论】:

【参考方案1】:

我试过跟随。截至目前工作 -

public class CustomControllerSelector : DefaultHttpControllerSelector

    //const string partName = "Webapi.Controllers";
    private readonly HttpConfiguration _config;

    public CustomControllerSelector(HttpConfiguration config)
        : base(config)
    
        _config = config;
    

    public override System.Web.Http.Controllers.HttpControllerDescriptor SelectController(HttpRequestMessage request)
    
        var _route = request.GetRouteData();

        var controllerName = base.GetControllerName(request);

        var type = _config.Services.GetAssembliesResolver();
        var controlles = _config.Services.GetHttpControllerTypeResolver().GetControllerTypes(type);

        object name;
        _route.Values.TryGetValue("route", out name);

        //No more hard coding
        var partName = controllers.FirstOrDefault().Namespace;
        var st = name as string;
        if (st != null)
        
            var conType = controlles.FirstOrDefault(a => a.Namespace == string.Format("0.1", partName, st));
                        if (conType != null)
                            return new System.Web.Http.Controllers.HttpControllerDescriptor(_config, controllerName, conType);
        

        return base.SelectController(request);
    

在 WebApiConfig.cs -

config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/controller/route/id",
            defaults: new  id = RouteParameter.Optional 
        ); 

测试路线 -

http://localhost:60957/api/Another/Route/a
http://localhost:60957/api/Another/Route2/aaaaa

【讨论】:

不,我的电话就像http://localhost:58892/api/customer 和标题accept : application/json;version=1 你所做的是静态的:( 检查我的课程CustomeControllerSelector.cs 是的,当控制器位于控制器文件夹 CustomerV1Controller.csCustomerV2Controller.cs 并且代码为 var versionedControllerName = string.Concat(controllerName, "V", version); HttpControllerDescriptor versionedControllerDescriptor; if (controllers.TryGetValue(versionedControllerName, out versionedControllerDescriptor)) return versionedControllerDescriptor; 时,它工作正常 我的代码中的Webapi.Controllers是什么我没有用过。 这是我的控制器命名空间的共同部分。您还需要更改路由代码以包含 route 部分。 我也在寻找同样的东西。如果找到会更新。

以上是关于找到了多种与控制器匹配的类型的主要内容,如果未能解决你的问题,请参考以下文章

命名空间更改 - 找到与名为“Home”的控制器匹配的多种类型

找到了与名为“Home”的控制器匹配的多种类型 - 在两个不同的区域中

MVC5 找到与名为“Home”的控制器匹配的多种类型

找到了多个与名为“帐户”的控制器匹配的类型。 MVC 4 & 使用 RouteConfig.CS

发现多个类型的家庭控制器

找到多个与名为“Login”的控制器匹配的类型