zoukankan      html  css  js  c++  java
  • 使Web API支持二级实体操作,兼对RESTFul风格API设计的疑惑。

    最近一直在纠结应该创建RESTFul风格的API还是以前那种函数调用风格的API。如果创建RESTFul风格的API,又有很多设计问题有待理清,这暂且不论,在用Web API创建RESTFul风格的API的时候,对于二级实体操作又该如何设计API接口呢?比如一个Client实体,它有很多属于它的Order实体,而每个Order实体又有很多Product实体,API接口如何设计才能更好的体现这种关系和操作呢?如果大家对此有想法,欢迎留言为我解惑。

    我目前尝试设计和实现一种层次性的API接口,我不确定这是否是最佳的做法,调用的时候看起来是这样的:

    /api/Clients/123/Orders/456/Products/789

    Route看起来是这样的:

    /api/{controller}/{id}/{subController1}/{subID1}/{subController2}/{subID2}

    当然,需要的话,可以继续往后追加subController3,4,5,6...

    而Controller应该看起来是什么样子的呢?我的做法是,分别为Client、Order和Product建立Controller:

    ClientsController

    ClientsOrdersController

    ClientsOrdersProductsConroller

    这样我可以将以上3个Controller的名字映射到{controller}、{subController1}、{subController2},抽象一点说,就是Controller名字的每一部分对应映射中的一个{controller}/{subcontrollerX}.

    剩下的一个问题就是如何让MVC引擎能将这个路由映射到正确的Controller上。我们都知道(其实我们不都知道,包括在研究这个问题之前的我),MVC引擎根据路由找Controller的操作之一要靠IHttpControllerSelector接口,默认情况下具体干活的就是DefaultHttpControllerSelector类,我要做的就是继承这个类,然后从路由数据中查看那些subController参数是否被映射上的具体数据,如果没有,就调用默认行为,如果有,就把所有的controller参数的值拼接成真正的controller名字返回,代码如下:

     1 using System;
     2 using System.Collections.Generic;
     3 using System.Linq;
     4 using System.Web.Http;
     5 using System.Web.Http.Dispatcher;
     6 using System.Net.Http;
     7 using System.Web.Http.Routing;
     8 
     9 namespace Ricky
    10 {
    11     public class HttpControllerSelectorEx : DefaultHttpControllerSelector
    12     {
    13         private HttpConfiguration _HttpCfg;
    14 
    15         public HttpControllerSelectorEx(HttpConfiguration cfg)
    16             : base(cfg)
    17         {
    18             _HttpCfg = cfg;
    19         }
    20 
    21         public override string GetControllerName(HttpRequestMessage request)
    22         {
    23             string name = base.GetControllerName(request);
    24             IHttpRouteData routeData = request.GetRouteData();
    25             IEnumerable<KeyValuePair<string, object>> subControllers = routeData.Values
    26                 .Where(d => d.Key.StartsWith("subController", StringComparison.CurrentCultureIgnoreCase));
    27             if (subControllers.Count() == 0)
    28                 return name;
    29 
    30             List<string> names = new List<string>(1 + subControllers.Count());
    31             names.Add(name);
    32             foreach (KeyValuePair<string,object> subController in subControllers)
    33             {
    34                 names.Add(subController.Value.ToString());
    35             }
    36 
    37             return string.Join("", names);
    38         }
    39     }
    40 }

    完成之后需要用我们的controller selector替换系统的默认设置。这在Global.asax.cs的Application_Start方法中做:

    1 GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpControllerSelector)
    2     , new Ricky.HttpControllerSelectorEx(GlobalConfiguration.Configuration));

    最后,我们修改一下路由设置:

     1 public static void Register(HttpConfiguration config)
     2 {
     3     config.Routes.MapHttpRoute(
     4         name: "DefaultApiWithSubControllers",
     5         routeTemplate: "api/{controller}/{id}/{subController}/{subID}/{subController2}/{subID2}",
     6         defaults: new
     7         {
     8             id = RouteParameter.Optional,
     9             subController = RouteParameter.Optional,
    10             subID = RouteParameter.Optional,
    11             subController2 = RouteParameter.Optional,
    12             subID2 = RouteParameter.Optional
    13         }
    14     );
    15 
    16     //config.Routes.MapHttpRoute(
    17     //    name: "DefaultApi",
    18     //    routeTemplate: "api/{controller}/{id}",
    19     //    defaults: new { id = RouteParameter.Optional }
    20     //);
    21 }

    由于我们的路由设置其实是扩展默认设置的,因此可以注释掉原来的默认设置。


    理解的越多,需要记忆的就越少
  • 相关阅读:
    Servlet生命周期
    DAO 开发模式的几个类
    Iterator用法
    mysql相似于oracle的to_char() to_date()方法
    Java Web页面跳转
    JSP 连接MySQL 5.1
    采用DOM进行表格的修改操作
    使用css让XML文件按照HTML的风格显示出来
    正则表达式Regular Expression
    什么是“堆”,"栈","堆栈","队列",它们的区别
  • 原文地址:https://www.cnblogs.com/Ricky81317/p/2875022.html
Copyright © 2011-2022 走看看