Маршрутизация на основе запрошенного типа данных в ASP.NET MVC - PullRequest
0 голосов
/ 04 августа 2010

Я пытаюсь записать REST-поведение в моем приложении ASP.NET MVC2, но мне трудно понять, как заставить маршруты работать так, как я хочу.

Я бы хотел, чтобы моя маршрутизация работала так:

/Users/Get/1 <- returns a regular HTML-based reply
/Users/Get.xml/1 <- returns the data from Get as XML
/Users/Get.json/1 <- returns the data as JSon

Я пытался настроить маршруты следующим образом:

routes.MapRoute("Rest", 
 "{controller}/{action}{format}/{id}" (...)

Но он жалуется, что мне нужен разделитель между {action} и {format}

также следующее:

routes.MapRoute("Rest",
     "{controller}/{action}.{format}/{id}" (...)

делает / Users / Get / 1 недействительным (это должен быть /Users/Get./1, что недопустимо)

Есть предложения?

------------- EDIT --------------------------------- ---

У меня есть одно решение прямо сейчас, но я не очень доволен им:

routes.MapRoute(
            "DefaultWithFormat", // Route name
            "{controller}/{action}.{format}/{id}", // URL with parameters
            new { controller = "Home", action = "Index", format = "HTML", id = UrlParameter.Optional } // Parameter defaults
        );
        routes.MapRoute(
            "Default", // Route name
            "{controller}/{action}/{id}", // URL with parameters
            new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
        );

Это работает как с /Users/Get.whwhatFormat/1, так и с / Users / Get / 1

Причина этого заключается в том, что когда я просто выполняю / Users / Get / 1 (без .format), он пропускает первый маршрут и переходит к следующему, который не включает формат. Для обработки возврата я создал ActionFilterAttribute и переопределил метод OnActionExecuted следующим образом:

var type = filterContext.RouteData.Values["format"];
if (type != null && attributes != null)
{
    if (type == "HTML") return;
    if (type.ToString().ToLower() == "xml" && attributes.Any(a => a.AllowedTypes.Any(a2 => a2 == ResponseType.XML)))
    {
        filterContext.Result = new XmlResult(filterContext.Controller.ViewData.Model);
        filterContext.HttpContext.Response.Clear();
        filterContext.HttpContext.Response.ContentType = "text/xml";
        return;
    }
    if (type.ToString().ToLower() == "json" && attributes.Any(a => a.AllowedTypes.Any(a2 => a2 == ResponseType.JSON)))
    {
        filterContext.Result = new JsonResult() { Data = (filterContext.Controller.ViewData.Model), JsonRequestBehavior = JsonRequestBehavior.AllowGet };
        filterContext.HttpContext.Response.Clear();
        filterContext.HttpContext.Response.ContentType = "text/json";
        return;
    }
}

И у меня также есть атрибут ResponseTypeAttribute, который позволяет мне украшать действия тем типом повторения, который они должны разрешать:

[AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = true)]
public sealed class ResponseTypeAttribute : Attribute
{
    List<ResponseType> allowedTypes;

    public List<ResponseType> AllowedTypes
    {
        get { return allowedTypes; }
        set { allowedTypes = value; }
    }

    public ResponseTypeAttribute(params ResponseType[] allowedTypes)
    {
        this.allowedTypes = new List<ResponseType>();
        this.allowedTypes.AddRange(allowedTypes);
    }


}

public enum ResponseType
{
    XML, JSON
}

XmlResult - это простой сериализатор объектов.

Ответы [ 5 ]

0 голосов
/ 04 августа 2010

Вы можете использовать регулярные выражения в вашем маршруте , а затем определить это "."в качестве дополнительного символа в вашем маршруте.

0 голосов
/ 04 августа 2010

Другая идея:

routes.MapRoute(
    "Rest1",
    "Users/Get/{id}.{format}",
    new { controller = "Users", action = "Get", format = "HTML" }
    );

А затем в методе контроллера добавьте некоторый код для восстановления идентификатора и формата

0 голосов
/ 04 августа 2010

Вы пытались установить значение по умолчанию для {format} из html?

0 голосов
/ 04 августа 2010

Может быть, это вариант (с использованием «/» вместо «.»):

routes.MapRoute(
        "Rest1",
        "Users/Get/{format}/{id}",
        new { controller = "Users", action = "Get", format = "HTML" }
        );

А затем

public class UsersController : Controller {
   public ActionResult Get(string format, int id) {
      switch (format) {
         case "json":
            break;
         case "xml":
            break;
         default:
            break;
      }
      return new ContentResult(); // Or other result as required.
   }
}
0 голосов
/ 04 августа 2010

Брэд Уилсон выступил с докладом под названием Advanced ASP.NET MVC2, где он показал пример того, как делать именно то, что вы хотите. Вы можете скачать слайды и пример кода здесь:

http://bradwilson.typepad.com/blog/talks.html

(Это первая беседа на странице, и, если я хорошо помню, URL-адреса с первой записью - первая тема в беседе.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...