您的位置:首页 > 其它

使Web API支持二级实体操作,兼对RESTFul风格API设计的疑惑。

2013-01-24 15:02 453 查看
最近一直在纠结应该创建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名字返回,代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Http;
using System.Web.Http.Dispatcher;
using System.Net.Http;
using System.Web.Http.Routing;

namespace Ricky
{
public class HttpControllerSelectorEx : DefaultHttpControllerSelector
{
private HttpConfiguration _HttpCfg;

public HttpControllerSelectorEx(HttpConfiguration cfg)
: base(cfg)
{
_HttpCfg = cfg;
}

public override string GetControllerName(HttpRequestMessage request)
{
string name = base.GetControllerName(request);
IHttpRouteData routeData = request.GetRouteData();
IEnumerable<KeyValuePair<string, object>> subControllers = routeData.Values
.Where(d => d.Key.StartsWith("subController", StringComparison.CurrentCultureIgnoreCase));
if (subControllers.Count() == 0)
return name;

List<string> names = new List<string>(1 + subControllers.Count());
names.Add(name);
foreach (KeyValuePair<string,object> subController in subControllers)
{
names.Add(subController.Value.ToString());
}

return string.Join("", names);
}
}
}


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

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


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

public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "DefaultApiWithSubControllers",
routeTemplate: "api/{controller}/{id}/{subController}/{subID}/{subController2}/{subID2}",
defaults: new
{
id = RouteParameter.Optional,
subController = RouteParameter.Optional,
subID = RouteParameter.Optional,
subController2 = RouteParameter.Optional,
subID2 = RouteParameter.Optional
}
);

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


由于我们的路由设置其实是扩展默认设置的,因此可以注释掉原来的默认设置。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: