Страница справки Web API с сообщением "Элемент с таким же ключом уже добавлен"

Я только что обновил страницу справки по веб-API до версии 2.1. Когда я попытался открыть страницу справки, я получил эту ошибку:

[ArgumentException: An item with the same key has already been added.]
System.ThrowHelper.ThrowArgumentException(ExceptionResource resource) +52
System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean add) +10695474
System.Collections.Generic.Dictionary`2.Add(TKey key, TValue value) +10
System.Web.Http.Description.ApiExplorer.TryExpandUriParameters(IHttpRoute route, HttpParsedRoute parsedRoute, ICollection`1 parameterDescriptions, String& expandedRouteTemplate) +407
System.Web.Http.Description.ApiExplorer.PopulateActionDescriptions(HttpActionDescriptor actionDescriptor, IHttpRoute route, String localPath, Collection`1 apiDescriptions) +258
System.Web.Http.Description.ApiExplorer.ExploreDirectRoute(HttpControllerDescriptor controllerDescriptor, CandidateAction[] candidates, IHttpRoute route) +358
System.Web.Http.Description.ApiExplorer.InitializeApiDescriptions() +410
System.Lazy`1.CreateValue() +416
System.Lazy`1.LazyInitValue() +152
System.Lazy`1.get_Value() +75
System.Web.Http.Description.ApiExplorer.get_ApiDescriptions() +40
CobaWebApi.Areas.HelpPage.HelpPageConfigurationExtensions.GetHelpPageApiModel(HttpConfiguration config, String apiDescriptionId) in e:\SPIKES\CobaWebApi\Areas\HelpPage\HelpPageConfigurationExtensions.cs:224
CobaWebApi.Areas.HelpPage.Controllers.HelpController.Api(String apiId) in e:\SPIKES\CobaWebApi\Areas\HelpPage\Controllers\HelpController.cs:38
lambda_method(Closure , ControllerBase , Object[] ) +180
System.Web.Mvc.ActionMethodDispatcher.Execute(ControllerBase controller, Object[] parameters) +59
System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary`2 parameters) +435
System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters) +60
System.Web.Mvc.Async.ActionInvocation.InvokeSynchronousActionMethod() +76
System.Web.Mvc.Async.AsyncControllerActionInvoker.<BeginInvokeSynchronousActionMethod>b__39(IAsyncResult asyncResult, ActionInvocation innerInvokeState) +36
System.Web.Mvc.Async.WrappedAsyncResult`2.CallEndDelegate(IAsyncResult asyncResult) +73
System.Web.Mvc.Async.WrappedAsyncResultBase`1.End() +136
System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag) +102
System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethod(IAsyncResult asyncResult) +49
System.Web.Mvc.Async.AsyncInvocationWithFilters.<InvokeActionMethodFilterAsynchronouslyRecursive>b__3f() +117
System.Web.Mvc.Async.<>c__DisplayClass48.<InvokeActionMethodFilterAsynchronouslyRecursive>b__41() +323
System.Web.Mvc.Async.<>c__DisplayClass33.<BeginInvokeActionMethodWithFilters>b__32(IAsyncResult asyncResult) +44
System.Web.Mvc.Async.WrappedAsyncResult`1.CallEndDelegate(IAsyncResult asyncResult) +47
System.Web.Mvc.Async.WrappedAsyncResultBase`1.End() +136
System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag) +102
System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethodWithFilters(IAsyncResult asyncResult) +50
System.Web.Mvc.Async.<>c__DisplayClass2b.<BeginInvokeAction>b__1c() +72
System.Web.Mvc.Async.<>c__DisplayClass21.<BeginInvokeAction>b__1e(IAsyncResult asyncResult) +185
System.Web.Mvc.Async.WrappedAsyncResult`1.CallEndDelegate(IAsyncResult asyncResult) +42
System.Web.Mvc.Async.WrappedAsyncResultBase`1.End() +133
System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag) +56
System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeAction(IAsyncResult asyncResult) +40
System.Web.Mvc.Controller.<BeginExecuteCore>b__1d(IAsyncResult asyncResult, ExecuteCoreState innerState) +34
System.Web.Mvc.Async.WrappedAsyncVoid`1.CallEndDelegate(IAsyncResult asyncResult) +70
System.Web.Mvc.Async.WrappedAsyncResultBase`1.End() +139
System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag) +59
System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag) +40
System.Web.Mvc.Controller.EndExecuteCore(IAsyncResult asyncResult) +44
System.Web.Mvc.Controller.<BeginExecute>b__15(IAsyncResult asyncResult, Controller controller) +39
System.Web.Mvc.Async.WrappedAsyncVoid`1.CallEndDelegate(IAsyncResult asyncResult) +62
System.Web.Mvc.Async.WrappedAsyncResultBase`1.End() +139
System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag) +59
System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag) +40
System.Web.Mvc.Controller.EndExecute(IAsyncResult asyncResult) +39
System.Web.Mvc.Controller.System.Web.Mvc.Async.IAsyncController.EndExecute(IAsyncResult asyncResult) +39
System.Web.Mvc.MvcHandler.<BeginProcessRequest>b__5(IAsyncResult asyncResult, ProcessRequestState innerState) +39
System.Web.Mvc.Async.WrappedAsyncVoid`1.CallEndDelegate(IAsyncResult asyncResult) +70
System.Web.Mvc.Async.WrappedAsyncResultBase`1.End() +139
System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag) +59
System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag) +40
System.Web.Mvc.MvcHandler.EndProcessRequest(IAsyncResult asyncResult) +40
System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.EndProcessRequest(IAsyncResult result) +38
System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +9628972
System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +155

Я отследил проблему до этих двух действий контроллера:

public class MyController : ApiController
{
    /// <summary>
    /// a quick brown fox
    /// </summary>
    /// <param name="request"></param>
    /// <returns></returns>
    [HttpGet]
    [ResponseType(typeof(OneResponse))]
    [Route("api/stuff/{Id}")]
    public IHttpActionResult GetOne([FromUri] OneRequest request)
    {
        return Ok(new OneResponse());
    }

    /// <summary>
    /// lazy dog
    /// </summary>
    /// <param name="request"></param>
    /// <returns></returns>
    [HttpGet]
    [ResponseType(typeof(ManyResponse))]
    [Route("api/stuff")]
    public IHttpActionResult GetMany([FromUri] ManyRequest request)
    {
        return Ok(new ManyResponse());
    }
}

Если я удалю [FromUri], страница справки будет отображаться без ошибок. Каким-то образом он считает две конечные точки одинаковыми, если я использую [FromUri].

Есть ли обходной путь для этого?

1 ответ

Решение

Это действительно ошибка в ApiExplorer. Подана следующая проблема: https://aspnetwebstack.codeplex.com/workitem/1683

Проблема здесь может быть воспроизведена с помощью одного действия. В приведенном выше сценарии я считаю, что у вас есть Id недвижимость в OneRequest,

Обходной путь:
Переименуйте свойство в шаблоне маршрута, чтобы оно имело другой случай, а не случай в свойстве модели. Так что здесь переименуйте параметр маршрута из Id в id в шаблоне, и это должно исправить вашу проблему.

public class OneRequest
{
     public int Id { get; set; }
     ....
}

[Route("api/stuff/{id}")]
public IHttpActionResult GetOne([FromUri] OneRequest request)

На самом деле Web API не должен делать чувствительный к регистру способ их сопоставления, и это кажется основной ошибкой, из-за которой вы видите ошибку.

Другие вопросы по тегам