gpt4 book ai didi

c# - 使用媒体类型对 ASP.NET Web API 2 进行版本控制

转载 作者:可可西里 更新时间:2023-11-01 08:20:57 27 4
gpt4 key购买 nike

我正在使用带有属性路由的 ASP.NET Web API 2,但我似乎无法使用媒体类型 application/vnd.company[.version].param[+json] 进行版本控制 去工作。

enter image description here

我收到以下错误:

The given key was not present in the dictionary.

源于在 FindActionMatchRequiredRouteAndQueryParameters() 方法中测试关键的 _actionParameterNames[descriptor]

foreach (var candidate in candidatesFound)
{
HttpActionDescriptor descriptor = candidate.ActionDescriptor;
if (IsSubset(_actionParameterNames[descriptor], candidate.CombinedParameterNames))
{
matches.Add(candidate);
}
}

来源:ApiControllerActionSelector.cs

经过进一步调试我意识到如果你有两个 Controller

[RoutePrefix("api/people")]
public class PeopleController : BaseApiController
{
[Route("")]
public HttpResponseMessage GetPeople()
{
}

[Route("identifier/{id}")]
public HttpResponseMessage GetPersonById()
{
}
}

[RoutePrefix("api/people")]
public class PeopleV2Controller : BaseApiController
{
[Route("")]
public HttpResponseMessage GetPeople()
{
}

[Route("identifier/{id}")]
public HttpResponseMessage GetPersonById()
{
}
}

您不能使用您的自定义 ApiVersioningSelector : DefaultHttpControllerSelector如上所述,因为它将测试所有具有相同 [RoutePrefix("api/people")] 的 Controller 的键,显然会抛出异常。

enter image description here enter image description here

只是为了确保选择了正确的 Controller

enter image description here

我不知道这是否是一个错误,但是使用路由 [RoutePrefix("api/v1/people")] 到版本 API 让我很难过。

注意:这在没有属性路由的情况下效果很好。

更新

public class ApiVersioningSelector : DefaultHttpControllerSelector
{
private HttpConfiguration _HttpConfiguration;
public ApiVersioningSelector(HttpConfiguration httpConfiguration)
: base(httpConfiguration)
{
_HttpConfiguration = httpConfiguration;
}



public override HttpControllerDescriptor SelectController(HttpRequestMessage request)
{
IDictionary<string, HttpControllerDescriptor> controllers = GetControllerMapping();

var attributedRoutesData = request.GetRouteData().GetSubRoutes();
var subRouteData = attributedRoutesData.LastOrDefault(); //LastOrDefault() will get PeopleController, FirstOrDefault will get People{version}Controller which we don't want

var actions = (ReflectedHttpActionDescriptor[])subRouteData.Route.DataTokens["actions"];
var controllerName = actions[0].ControllerDescriptor.ControllerName;


//For controller name without attribute routing
//var controllerName = (string)routeData.Values["controller"];

HttpControllerDescriptor oldControllerDescriptor;
if (controllers.TryGetValue(controllerName, out oldControllerDescriptor))
{
var apiVersion = GetVersionFromMediaType(request);

var newControllerName = String.Concat(controllerName, "V", apiVersion);

HttpControllerDescriptor newControllerDescriptor;
if (controllers.TryGetValue(newControllerName, out newControllerDescriptor))
{
return newControllerDescriptor;
}
return oldControllerDescriptor;
}
return null;
}


private string GetVersionFromMediaType(HttpRequestMessage request)
{
var acceptHeader = request.Headers.Accept;

var regularExpression = new Regex(@"application\/vnd\.mycompany\.([a-z]+)\.v([0-9]+)\+json",
RegexOptions.IgnoreCase);

foreach (var mime in acceptHeader)
{
var match = regularExpression.Match(mime.MediaType);
if (match != null)
{
return match.Groups[2].Value;
}
}
return "1";
}

}

最佳答案

感谢您分享您的代码。我已经修改了你的版本 Controller 选择器,如下所示,并尝试了一些场景,它似乎运行良好。您可以尝试像下面这样更新您的 Controller 选择器,看看它是否有效?

    public override HttpControllerDescriptor SelectController(HttpRequestMessage request)
{
HttpControllerDescriptor controllerDescriptor = null;

// get list of all controllers provided by the default selector
IDictionary<string, HttpControllerDescriptor> controllers = GetControllerMapping();

IHttpRouteData routeData = request.GetRouteData();

if (routeData == null)
{
throw new HttpResponseException(HttpStatusCode.NotFound);
}

//check if this route is actually an attribute route
IEnumerable<IHttpRouteData> attributeSubRoutes = routeData.GetSubRoutes();

var apiVersion = GetVersionFromMediaType(request);

if (attributeSubRoutes == null)
{
string controllerName = GetRouteVariable<string>(routeData, "controller");
if (controllerName == null)
{
throw new HttpResponseException(HttpStatusCode.NotFound);
}

string newControllerName = String.Concat(controllerName, "V", apiVersion);

if (controllers.TryGetValue(newControllerName, out controllerDescriptor))
{
return controllerDescriptor;
}
else
{
throw new HttpResponseException(HttpStatusCode.NotFound);
}
}
else
{
// we want to find all controller descriptors whose controller type names end with
// the following suffix(ex: CustomersV1)
string newControllerNameSuffix = String.Concat("V", apiVersion);

IEnumerable<IHttpRouteData> filteredSubRoutes = attributeSubRoutes.Where(attrRouteData =>
{
HttpControllerDescriptor currentDescriptor = GetControllerDescriptor(attrRouteData);

bool match = currentDescriptor.ControllerName.EndsWith(newControllerNameSuffix);

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;
}

// Get a value from the route data, if present.
private static T GetRouteVariable<T>(IHttpRouteData routeData, string name)
{
object result = null;
if (routeData.Values.TryGetValue(name, out result))
{
return (T)result;
}
return default(T);
}

关于c# - 使用媒体类型对 ASP.NET Web API 2 进行版本控制,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19835015/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com