2

У меня есть Asp.net MVC приложение, которое в настоящее время хорошо работает с использованием модели связующего по умолчанию и URLs со сложными параметрами, как это:ASP.net MVC - Использование модели Binder без значений строки запроса или фантазии маршрутов

example.com/Controller/Action?a=hello & Ь = & мир с = 1 & д = 2 & е = 3 (обратите внимание на знак вопроса)

различные адреса автоматически отображаются на параметры метода действия с помощью встроенного в модельном связующем. Я хотел бы продолжить использование стандартного связующего, но мне нужно избавиться от строки запроса. Мы хотим, чтобы поставить эти URLs позади CDN that does not support resources that vary by query strings (Amazon Cloud front) так что нам нужно, чтобы удалить знак вопроса из наших URLs и сделать что-то глупое, как этот

example.com/Controller/Action/a=hello & б = мир & с = 1 & d = 2 & е = 3 (без вопросительного знака)

Эти адреса используются только с помощью AJAX, так что я не заинтересован в создании им пользователя или SEO дружественных. Я хочу просто оставить вопросительный знак и сохранить все мои коды точно так же. Сцепка есть, я не уверен, как продолжать использовать связующее для модели MVC, и отказаться от нее было бы большой работой.

Я не хочу использовать сложный маршрут на карту моих объектов like this question did и, вместо этого, я планирую использовать один простой маршрут, как один ниже

routes.MapRoute(
     "NoQueryString",     // Route name 
     "NoQueryString/{action}/{query}", // 'query' = querystring without the ? 
     new { 
      controller = "NoQueryString", 
      action = "Index", 
      query = "" } // want to parse with model binder - By NOT ROUTE 
    ); 

Вариант 1 (предпочтительный): OnActionExecuting Я планирую использовать значение «запрос» на маршруте выше, чтобы вставить старую строку запроса в связующее устройство модели по умолчанию до того, как действия контроллера выполняются с использованием метода OnActionExecuting в моем контроллере. Тем не менее, я немного не уверен, могу ли я просто добавить знак вопроса. Могу ли я это сделать? Как бы вы рекомендовали изменить URL?

Вариант 2: Пользовательские модели Binder я также мог бы сделать какой-то заказ Model Binder, который просто говорит модель по умолчанию Связыватель для лечения на «запрос» значение как строку запроса. Вы бы предпочли этот метод? Можете ли вы указать мне пример?

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

ответ

5

Вы можете использовать поставщик пользовательского значения с Catchall маршруту:

routes.MapRoute(
    "NoQueryString", 
    "NoQueryString/{controller}/{action}/{*catch-em-all}", 
    new { controller = "Home", action = "Index" } 
); 

и поставщик значения:

public class MyCustomProvider : ValueProviderFactory 
{ 
    public override IValueProvider GetValueProvider(ControllerContext controllerContext) 
    { 
     var value = controllerContext.RouteData.Values["catch-em-all"] as string; 
     var backingStore = new Dictionary<string, object>(); 
     if (!string.IsNullOrEmpty(value)) 
     { 
      var nvc = HttpUtility.ParseQueryString(value); 
      foreach (string key in nvc) 
      { 
       backingStore.Add(key, nvc[key]); 
      } 
     } 
     return new DictionaryValueProvider<object>(
      backingStore, 
      CultureInfo.CurrentCulture 
     ); 
    } 
} 

, который вы регистрируетесь в Application_Start:

ValueProviderFactories.Factories.Add(new MyCustomProvider()); 

и сейчас все, что осталось - это модель:

public class MyViewModel 
{ 
    public string A { get; set; } 
    public string B { get; set; } 
    public string C { get; set; } 
    public string D { get; set; } 
    public string E { get; set; } 
} 

и контроллер:

public class HomeController : Controller 
{ 
    [ValidateInput(false)] 
    public ActionResult Index(MyViewModel model) 
    { 
     return View(model); 
    } 
} 

, а затем перейти к: NoQueryString/Home/Index/a=hello&b=world&c=1&d=2&e=3. Index поражен, и модель связана.

Примечание: Обратите внимание на действие контроллера. Это, вероятно, понадобится, потому что ASP.NET не позволит вам использовать специальные символы, такие как & как часть URI. Кроме того, возможно, потребуется настроить ваш Web.config немного:

<httpRuntime requestValidationMode="2.0" requestPathInvalidCharacters=""/> 

Для получения дополнительной информации об этих ухищрениях убедитесь, что вы прочитали Скотт Hansleman-х blog post.

+0

Бланк проверки запроса немного меня испугал. Нужно ли мне это, если бы я только добавил вопросительный знак обратно на уровне контроллера, а не при запуске приложения? – Glenn

+0

Я предполагаю, что могу кодировать целую строку запроса, но было бы неплохо избежать двойного кодирования, поскольку значения уже закодированы. – Glenn

+1

@ Гленн, я не понимаю ваш вопрос. Валидация важна, потому что в противном случае ASP.NET выдаст исключение, заявив, что вы пытались отправить опасных символов как часть вашего маршрута. Обычно символ '&' должен использоваться только в строке запроса, которая не является вашим делом, и вам нужно обойти ее, если вы когда-либо хотели поддерживать URL-адреса, как этот. –

2

В чем проблема с «сложными» определениями маршрутизации? Маршруты, с которыми вы связаны, очень просты. Значения по умолчанию могут пройти долгий путь. Лучше использовать возможности по умолчанию MVC, чтобы включить:

example.com/Controller/Action/a=hello&b=world&c=1&d=2&e=3 

в

example.com/Controller/Action/hello/world/1/2/3 

чем начать заново жгуты основные биты, как RouteValue обработки (вариант 1) или реализации пользовательской модели связующего.

Я знаю, что это не отвечает на ваш вопрос, но кажется, что вы сделали выбор, не используя возможности маршрутизации MVC, не понимая технических последствий.Вы знаете, что говорят: «Хорошие друзья останавливают друг друга от глупостей».

+0

У меня есть более дюжины маршрутов, каждый из которых имеет несколько значений. Чтобы использовать ваш метод, мне пришлось бы отображать сотни отдельных свойств. Я думаю, что избегать этого труда - вот почему модель связующего существует. Модельное связующее позволяет изменять значения маршрута только путем изменения модели представления. Например, если некоторые из моих методов действий совместно используют общие объекты ViewModel в качестве одного из своих puts, а также используют разные входы, все, что мне нужно, это один маршрут и один поставщик значений. Кроме того, если позже мне нужно добавить другое свойство, я могу просто добавить свойство к объекту модели общего представления, и я закончен. – Glenn

+0

Я ценю ваши отзывы. Извините, если я не смог адекватно передать сложность используемых URL. Методы сопоставления, как вы описали, хорошо работают для более простых, удобных для пользователя URL-адресов ... это совсем не так. – Glenn

+1

@Glenn - проблем нет. Из другого вопроса, с которым вы связались, звучало так, будто у вас было небольшое количество маршрутов, а не тысячи комбинаций. Тем не менее даже с дюжиной маршрутов я бы посмотрел, как использовать значения по умолчанию. Ответ @Darin Dimitrov действительно хорош, как и всегда, но я не уверен, что вам это нужно. – jfar