Как я могу расширить поведение согласования контента в MVC4?

Я работаю над дизайном RESTful API, и один из вопросов, которые у меня есть о согласовании контента, я разместил на сайте Programmers StackExchange здесь.

Исходя из этого, меня интересует, как я буду поддерживать следующее поведение в MVC4:

  1. Если в URL-адресе указано расширение (например, GET /api/search.json или /api/search.xml), переопределите поведение согласования содержимого по умолчанию в MVC4.
  2. Если расширение не указано, используйте поведение по умолчанию для проверки значения заголовка accept на application/xml или application.json.

Каким будет самый чистый/самый простой способ захватить это расширение и изменить поведение согласования контента?


person Brandon Linton    schedule 14.03.2012    source источник


Ответы (1)


Для этого вы можете использовать UriPathExtensionMapping в средствах форматирования. Эти сопоставления позволяют вам «назначить» расширение средству форматирования, чтобы они имели приоритет во время согласования содержимого. Также нужно добавить маршрут, чтобы запросы с «расширением» тоже принимались. В приведенном ниже коде показаны изменения, необходимые в шаблоне по умолчанию для включения этого сценария.

    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

        routes.MapHttpRoute(
            name: "Api with extension",
            routeTemplate: "api/{controller}.{ext}/{id}",
            defaults: new { id = RouteParameter.Optional, ext = RouteParameter.Optional }
        );

        routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );

        routes.MapRoute(
            name: "Default",
            url: "{controller}/{action}/{id}",
            defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
        );
    }

    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();

        RegisterGlobalFilters(GlobalFilters.Filters);
        RegisterRoutes(RouteTable.Routes);

        GlobalConfiguration.Configuration.Formatters.XmlFormatter.AddUriPathExtensionMapping("xml", "text/xml");
        GlobalConfiguration.Configuration.Formatters.JsonFormatter.AddUriPathExtensionMapping("json", "application/json");
        BundleTable.Bundles.RegisterTemplateBundles();
    }
person carlosfigueira    schedule 14.03.2012
comment
Потрясающий! Эти расширения форматирования также позволяют вам управлять им через параметр строки запроса, что, как мне кажется, мне больше нравится. - person Brandon Linton; 14.03.2012
comment
@BrandonLinton - как у вас работает параметр строки запроса? вам нужно было сделать что-то дополнительно для его перехвата и преобразования? - person drzaus; 07.05.2012
comment
@drzaus Вместо AddUriPathExtensionMapping используйте операцию расширения AddQueryStringMapping, например: formatter.AddQueryStringMapping("returnType", "json", "application/json"); - person Brandon Linton; 07.05.2012
comment
Можно ли поставить расширение в конце, чтобы вместо /api/products.xml/6 можно было использовать /api/products/6.xml? Это позволит браузерам, таким как IE, отображать данные вместо запроса на загрузку. Я пробовал routeTemplate: "api/{controller}/{id}.{ext}", но это вызывает ошибку при синтаксическом анализе id как целого числа. - person MCattle; 11.12.2012
comment
Я заработал, это был вопрос порядка добавления маршрутов, где маршруты с {ext} должны появляться перед маршрутами без. - person MCattle; 11.12.2012
comment
Я новичок в MVC, но я не могу заставить это работать. Кто-нибудь пробовал это с VS 2012 и 4.5? Каждый раз, когда я использую расширение .xml, я всегда получаю ошибку 404. - person codeputer; 25.12.2012