在我的WebApiConfig :: Register(...)中,我用自己的控制器选择器替换了HttpControllerSelector。当我发出POST请求时,正确调用了SelectController成员,并返回一个具有正确控制器类型的ControllerDescriptor。 但是HttpControllerDispatcher正在提出一个异常,说“字典中没有给出”。任何人都知道如何调试这样的错误?
完整的例外是消息:
The given key was not present in the dictionary.","ExceptionType":"System.Collections.Generic.KeyNotFoundException","StackTrace":" at System.Collections.Generic.Dictionary`2.get_Item(TKey key)\r\n
at System.Web.Http.Controllers.ApiControllerActionSelector.ActionSelectorCacheItem.FindActionMatchRequiredRouteAndQueryParameters(IEnumerable`1 candidatesFound)\r\n
at System.Web.Http.Controllers.ApiControllerActionSelector.ActionSelectorCacheItem.FindMatchingActions(HttpControllerContext controllerContext, Boolean ignoreVerbs)\r\n
at System.Web.Http.Controllers.ApiControllerActionSelector.ActionSelectorCacheItem.SelectAction(HttpControllerContext controllerContext)\r\n
at System.Web.Http.Controllers.ApiControllerActionSelector.SelectAction(HttpControllerContext controllerContext)\r\n
at System.Web.Http.ApiController.ExecuteAsync(HttpControllerContext controllerContext, CancellationToken cancellationToken)\r\n
at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__1.MoveNext()"
这是我的控制器选择器:
public class Namespace_HTTP_Controller_Selector : IHttpControllerSelector
{
private readonly HttpConfiguration _configuration;
private readonly Lazy<Dictionary<string, HttpControllerDescriptor>> _controller;
public Namespace_HTTP_Controller_Selector(HttpConfiguration Config)
{
_configuration = Config;
_controller = new Lazy<Dictionary<string, HttpControllerDescriptor>>(Initialize_Controller_Dictionary);
}
public HttpControllerDescriptor SelectController(HttpRequestMessage Request)
{
var Route_Data = Request.GetRouteData();
if(Route_Data == null)
{
throw new HttpResponseException(HttpStatusCode.NotFound);
}
var Controller_Name = Get_Controller_Name(Route_Data);
if(Controller_Name == null)
{
throw new HttpResponseException(HttpStatusCode.NotFound);
}
var Name_Space = Get_Version(Route_Data);
if (Name_Space == null)
{
throw new HttpResponseException(HttpStatusCode.NotFound);
}
var Controller_Key = String.Format(CultureInfo.InvariantCulture, "{0}.{1}", Name_Space, Controller_Name);
HttpControllerDescriptor Descriptor;
if(_controller.Value.TryGetValue(Controller_Key, out Descriptor))
{
return Descriptor;
}
throw new HttpResponseException(HttpStatusCode.NotFound);
}
public IDictionary<string, HttpControllerDescriptor> GetControllerMapping()
{
return _controller.Value;
}
private Dictionary<string, HttpControllerDescriptor> Initialize_Controller_Dictionary()
{
var Dictionary = new Dictionary<string, HttpControllerDescriptor>(StringComparer.OrdinalIgnoreCase);
var Assemblies_Resolver = _configuration.Services.GetAssembliesResolver();
var Controller_Resolver = _configuration.Services.GetHttpControllerTypeResolver();
var Controller_Types = Controller_Resolver.GetControllerTypes(Assemblies_Resolver);
foreach(var ct in Controller_Types)
{
var Segments = ct.Namespace.Split(Type.Delimiter);
var Controller_Name = ct.Name.Remove(ct.Name.Length - DefaultHttpControllerSelector.ControllerSuffix.Length);
var Controller_Key = string.Format(CultureInfo.InvariantCulture, "{0}.{1}", Segments[Segments.Length - 1], Controller_Name);
if(Dictionary.Keys.Contains(Controller_Key) == false)
{
Dictionary[Controller_Key] = new HttpControllerDescriptor(_configuration, ct.Name, ct);
}
}
return Dictionary;
}
private T Get_Route_Variable<T>(IHttpRouteData Route_Data, string Name)
{
object Result;
if(Route_Data.Values.TryGetValue(Name, out Result))
{
return (T)Result;
}
return default(T);
}
private string Get_Controller_Name(IHttpRouteData Route_Data)
{
var SubRoute = Route_Data.GetSubRoutes().FirstOrDefault();
if( SubRoute == null )
{
return null;
}
var Data_Token_Value = SubRoute.Route.DataTokens.First().Value;
if(Data_Token_Value == null)
{
return null;
}
var Controller_Name = ((HttpActionDescriptor[])Data_Token_Value).First().ControllerDescriptor.ControllerName.Replace("Controller", string.Empty);
return Controller_Name;
}
private string Get_Version(IHttpRouteData Route_Data)
{
var Sub_Route_Data = Route_Data.GetSubRoutes().FirstOrDefault();
if(Sub_Route_Data== null)
{
return null;
}
return Get_Route_Variable<string>(Sub_Route_Data, "apiVersion");
}
}
答案 0 :(得分:3)
这是因为在返回描述符之前,您没有在请求中设置子路由数据。
HttpControllerDescriptor Descriptor;
if(_controller.Value.TryGetValue(Controller_Key, out Descriptor))
{
var subRoutes = Route_Data.GetSubRoutes();
IEnumerable<IHttpRouteData> filteredSubRoutes = subRoutes.Where(attrRouteData =>
{
HttpControllerDescriptor currentDescriptor = ((HttpActionDescriptor[])Route_Data.Route.DataTokens["actions"]).First().ControllerDescriptor;
return currentDescriptor != null && currentDescriptor.ControllerName.Equals(Descriptor.ControllerName, StringComparison.OrdinalIgnoreCase);
});
Route_Data.Values["MS_SubRoutes"] = filteredSubRoutes.ToArray();
return Descriptor;
}
答案 1 :(得分:0)
public class CustomSelectorController : DefaultHttpControllerSelector
{
HttpConfiguration _config;
public CustomSelectorController(HttpConfiguration config) : base(config)
{
_config = config;
}
public override HttpControllerDescriptor SelectController(HttpRequestMessage request)
{
IHttpRouteData routeData = request.GetRouteData();
IEnumerable<IHttpRouteData> attributeSubRoutes = routeData.GetSubRoutes();
var actions = attributeSubRoutes.LastOrDefault()?.Route?.DataTokens["actions"] as HttpActionDescriptor[];
var controllerName = "";
if (actions != null && actions.Length > 0)
{
controllerName = actions[0].ControllerDescriptor.ControllerName;
}
IEnumerable<string> headerValues = null;
//Custom Header Name to be check version
if (request.Headers.TryGetValues("Accept-Version", out headerValues))
{
var apiVersion = headerValues.First().ToUpper();
if (apiVersion == "V2")
{
controllerName = controllerName + apiVersion;
}
}
HttpControllerDescriptor controllerDescriptor = null;
IEnumerable<IHttpRouteData> filteredSubRoutes = attributeSubRoutes.Where(attrRouteData =>
{
HttpControllerDescriptor currentDescriptor = GetControllerDescriptor(attrRouteData);
bool match = currentDescriptor.ControllerName.Equals(controllerName);
if (match && (controllerDescriptor == null))
{
controllerDescriptor = currentDescriptor;
}
return match;
});
routeData.Values["MS_SubRoutes"] = filteredSubRoutes.ToArray();
return controllerDescriptor;
}
private HttpControllerDescriptor GetControllerDescriptor(IHttpRouteData routeData)
{
return ((HttpActionDescriptor[])routeData.Route.DataTokens["actions"]).First().ControllerDescriptor;
}
}