ASP.net MVC - используйте связыватель модели без значений строки запроса или необычных маршрутов - PullRequest
2 голосов
/ 26 января 2011

У меня есть Asp.net MVC приложение, которое в настоящее время хорошо работает с использованием связывателя модели по умолчанию и URL-адресов со сложными параметрами, такими как:

example.com / Controller / Action? A = привет & b = world & c = 1 & d = 2 & e = 3 (обратите внимание на знак вопроса)

Различные URL-адреса автоматически отображаются на параметры метода действия с использованием встроенного связывателя модели. Я хотел бы продолжить использовать стандартную модель связующего, но мне нужно избавиться от строки запроса. Мы хотим поместить эти URL-адреса за CDN, который не поддерживает ресурсы, которые различаются в зависимости от строки запроса (фронт Amazon Cloud) , поэтому нам нужно удалить вопросительный знак из наших URL-адресов и сделать что-то глупое, как это

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

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

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

   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 Я планирую использовать значение catchall «query» на вышеприведенном маршруте, чтобы вставить старую строку запроса в связыватель модели по умолчанию перед выполнением действий контроллера с использованием метода OnActionExecuting в моем контроллере. Тем не менее, я немного не уверен, смогу ли я просто добавить знак вопроса. Могу ли я сделать это? Как бы вы порекомендовали изменить URL?

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

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

Ответы [ 2 ]

5 голосов
/ 26 января 2011

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

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 и привязка модели.

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

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

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

2 голосов
/ 26 января 2011

В чем проблема со «сложными» определениями маршрутизации?Маршруты, на которые вы ответили, очень просты.Значения по умолчанию могут иметь большое значение.Лучше использовать возможности 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 без понимания технических последствий.Вы знаете, что они говорят: «хорошие друзья мешают друг другу делать глупости».

...