Как должен работать поставщик связующих моделей C # Web API?

#asp.net #asp.net-mvc #asp.net-web-api #asp.net-mvc-5 #asp.net-web-api2

#asp.net #asp.net-mvc #asp.net-web-api #asp.net-mvc-5 #asp.net-web-api2

Вопрос:

У меня есть следующее:

  • URL-адрес запроса: ‘endpoint/1,2,3?q=foo’
  • действие, к которому привязан запрос: панель открытых объектов ([ModelBinder] Список < T> идентификаторов, [FromUri] строка q)

Я хочу сопоставить фрагмент «1,2,3» с параметром «ids», поэтому я создал ModelBinderProvider в соответствии с этой ссылкой, которая должна вызывать надлежащую связующую модель.

 public class MyModelBinderProvider: ModelBinderProvider
{
    public override IModelBinder GetBinder(HttpConfiguration configuration, Type modelType)
    {
        IModelBinder modelBinder = null;

        if (modelType.IsGenericType amp;amp; (modelType.GetGenericTypeDefinition() == typeof(List<>)))
        {
            modelBinder = new ListModelBinder();   
        }

        return modelBinder;
    }
}
 

Я зарегистрировал поставщика в Global.asax следующим образом:

 GlobalConfiguration.Configuration.Services.Insert(typeof(ModelBinderProvider), 0, new MyModelBinderProvider());
 

Причина: я создал этого поставщика, потому что я хочу, независимо от того, что такое T (‘1,2,3’ или ‘один, два, три’), привязка к работе.

Проблема: допустим, T равно ‘int’; каждый раз, когда отправляется запрос, параметром ‘ModelType’ всегда является ‘int’, а не то, что я ожидаю — ‘List<int>’, поэтому запрос обрабатывается неправильно.

Странная вещь: выполнение чего-то подобного работает, но T является специализированным, и поэтому я не хочу:

 var simpleProvider = new SimpleModelBinderProvider(typeof(List<int>), new ListModelBinder());
GlobalConfiguration.Configuration.Services.Insert(typeof(ModelBinderProvider), 0, simpleProvider);
 

Я не вижу, что я делаю неправильно, почему параметр ‘ModelType’ не является ожидаемым значением?

Комментарии:

1. Пожалуйста, поясните, почему вы хотели бы это сделать? В каком реальном сценарии вы считаете это полезным? Таким образом, это действительно похоже на взлом чего-то, что может иметь более сложное решение с совершенно другим URI.

Ответ №1:

Это очень старый вопрос, но у меня была аналогичная проблема с устаревшим кодом.

Запятые зарезервированы, и их следует избегать, хотя в некоторых случаях они работают, но если вы действительно хотите их использовать…

Я думаю, что это скорее проблема маршрута, чем связующего для модели, когда «1,2,3» является частью пути URL. Предполагая это, я написал небольшой обработчик маршрута, который делает трюк (пожалуйста, простите очень простой переводчик «слово в целое число»).

CsvRouteHandler получает массив идентификаторов из URL и помещает его в RouteData в виде массива целых чисел. Если исходный массив содержит такие слова, как one, two или three, он преобразует каждое значение в int .

MvcRouteHandler

 protected override IHttpHandler GetHttpHandler(System.Web.Routing.RequestContext requestContext)
{
    var idArrayParameter = requestContext.RouteData.Values["idArray"] != null ? requestContext.RouteData.Values["idArray"].ToString() : null;
    if (string.IsNullOrEmpty(idArrayParameter))
    {
        return base.GetHttpHandler(requestContext);
    }

    requestContext.RouteData.Values.Remove("idArray"); // remove the old array from routedata

    // Note: it is horrible and bugged but and you probably have your own translation method :)
    string[] idArray = idArrayParameter.Split(',');
    int[] ids = new int[idArray.Length];

    for(int i = 0; i < idArray.Length; i  )
    {
        if (!int.TryParse(idArray[i], out ids[i]))
        {
            switch (idArray[i])
            {
                case "one":
                    ids[i] = 1;
                    break;
                case "two":
                    ids[i] = 2;
                    break;
                case "three":
                    ids[i] = 3;
                    break;
            }
        }
    }

    requestContext.RouteData.Values.Add("Id", ids);

    return base.GetHttpHandler(requestContext);

}
}
 

Конфигурация маршрута:

     routes.Add(
        name: "Id Array Route",
        item: new Route(
            url: "endpoint/{idArray}",
            defaults: new RouteValueDictionary(new { controller = "Test", action = "Index" }),
            routeHandler: new CsvRouteHandler())
    );