代码之家  ›  专栏  ›  技术社区  ›  Yngve B-Nilsen

ASP.NET MVC中基于请求数据类型的路由

  •  0
  • Yngve B-Nilsen  · 技术社区  · 15 年前

    我正在尝试将REST行为写入我的ASP.NETMVC2应用程序,但我很难弄清楚如何使路由按我所希望的方式工作。

    /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,这是不可接受的)

    有什么建议吗?

    我现在有一个解决方案,但我并不满意:

    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.whateverFormat/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 回复  |  直到 15 年前
        1
  •  0
  •   apolka    15 年前

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

    (这是页面上的第一个话题,如果我记得很清楚的话,restfulurl是第一个话题。)

        2
  •  0
  •   Jordan S. Jones    15 年前

    {format} 属于 html ?

        3
  •  0
  •   Manfred    15 年前

    可能这是一个选项(使用“/”而不是“.”):

    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.
       }
    }
    
        4
  •  0
  •   meeron    15 年前

    另一个想法:

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

    然后在controller方法中添加一些代码来检索id和格式

        5
  •  0
  •   Radu094    15 年前
    推荐文章