Я пытаюсь записать 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 - это простой сериализатор объектов.