我正在使用ASP.NET Web API 2为RESTful API构建原型。我们假设我有三个实体:客户,许可证和用户。每个客户都有一组许可证和用户。在语义上,在我看来资源URI应如下所示:
myurl/api/customers for accessing all customers
myurl/api/customers/{cid} for accessing the customer {cid}
myurl/api/customers/{cid}/licences for accessing all licences of customer {cid}
myurl/api/customers/{cid}/licences/{lid} for accessing the licence {lid} of customer {cid}
用户也一样。预期的语义允许例如两个用户如果属于不同的客户则具有相同的id。除了许可证实体(决定尚未最终)之外,每个客户都将拥有一个专用数据库,因此这个域和资源路径中没有重叠,如
myurl/api/users
在“加入所有客户数据库中的所有用户表”的方式中才有意义。
使用属性路由很容易实现此设置。但是,所有方法都必须在同一个控制器中实现,因为来自不同控制器的方法不能共享相同的前缀AFAIK。
实际的应用程序将包含比三个更多的实体,所以我希望控制器的实现变得非常庞大。我现在的问题是,如何将方法拆分为不同的控制器?我想过使用一个主控制器,它只是将要完成的工作分配给另一个控制器。例如
[Route("{customer:int}/licences/{licence:int}")]
public HttpResponseMessage GetLicence(int customer, int licence)
{
// pretend the called method is static
return LicenceController.GetLicence(customer, licence);
}
但是,我不知道如何正确实现这个:我应该为每个调用创建一个新的LicenceController吗?或者拥有这种类型的属性并调用它的方法?实际上实现了一些静态方法?
另一个缺点是,它引入了选择器和实现控制器类之间的硬编码依赖关系,我觉得这不是一个干净的解决方案。
我想出了一个使用这样的资源路径的解决方法:
myurl/api/licences/customer-{cid} for accessing all licences of customer {cid}
myurl/api/licences/customer-{cid}/{lid} for accessing the licence {lid} of customer {cid}
这很有效,但会弄乱同构语义IMO。我知道我可以写一个自定义选择器类,但这似乎是一些工作,以使其正确。
所以我的问题是,将处理传入HTTP消息的代码分割成单独的控制器的最佳(也许是最有效的)方法是什么,以便松散耦合并且资源语义是连贯的?
答案 0 :(得分:1)
你将有两个控制器。一个返回客户,一个返回许可证。对于客户,不需要使用属性,因为默认值很好:
public class CustomersController : ApiController
{
// GET: api/Customers
public IEnumerable<Customer> Get()
{
return new List<Customer>
{
new Customer { Id = 1, Name = "Wayne" },
new Customer { Id = 2, Name = "John" }
};
}
// GET: api/Customers/5
public Customer Get(int id)
{
return new Customer { Id = 1, Name = "Wayne" };
}
}
然后,您可以在控制器上为RoutePrefix
添加api/Customers/1/licences
的{{1}}属性,其余部分可由Route
处理。我将Controller命名为CustomerLicencesController
,因为您可能希望拥有许可证控制器来获取特定许可证或所有许可证,例如api/licences
或api/licences/1
。
[RoutePrefix("api/customers/{customer}/licences")]
public class CustomerLicencesController : ApiController
{
// GET: api/Customers/1/licences
[Route("")]
public IEnumerable<Licence> Get(int customer)
{
return new List<Licence>
{
new Licence { Id = 1, Name = "Test" },
new Licence { Id = 2, Name = "Test2" }
};
}
// GET: api/Customers/1/licences/1
[Route("{id}")]
public Licence Get(int customer, int id)
{
return new Licence { Id = 1, Name = "Test" };
}
}
有关路线属性的更多信息,请查看this。