web api 2 学习笔记 (OData RPC)
Web API 2 + OData v4
等我熟悉了再写一个完整系列. 这里只给我自己看
builder :
//Entity RPC 写方 builder.Namespace = "RPC"; var gettotalFn = builder.EntityType<Voucher>().Collection.Function("getTotal"); //Function 是用于安全请求的 gettotalFn.Returns<int>(); //一般都是返回 Task<IHttpActionResult>, 所以这里写什么不太重要,也不会有什么error var setTotalAction = builder.EntityType<Voucher>().Collection.Action("setTotal"); setTotalAction.Returns<int>();
setTotalAction.ReturnsFromEntitySet<LoginPerson>("loginPersons"); //如果返回entity要这样写,loginPersons 如果之前有命名过,那么要写一模一样哦
setTotalAction.ReturnsCollectionFromEntitySet<LoginPerson>("loginPersons") //for List<LoginPersons>
//官网的写法 var setTotalTwoAction = builder.EntityType<Voucher>().Collection.Action("setTotalTwo"); setTotalTwoAction.Returns<int>(); setTotalTwoAction.Parameter<string>("name");
setTotalTwoAction..CollectionEntityParameter<string>("names"); //List<string> 的写法 //Global RPC 写法 var getDataAction = builder.Action("setData"); //setData route name not method name oh!,所以我们要写符号也行,e.g. 通过[ODataRoute("abc.setData")] 也是可以调用到的。 getDataAction.Returns<int>(); var getDataFn = builder.Function("getData"); getDataFn.Returns<int>();
.Collection.Action 和 .Action 是有区别的, 一个表示 /api/Orders/RPC.xxx 另一个是 /api/Orders(5)/RPC.xxx
entity controller :
//GET : //localhost:55573/api/vouchers?$skip=5&customeData=5 public IQueryable<Voucher> get(ODataQueryOptions<Voucher> options, int customeData) { return db.vouchers; } //DELETE : //localhost:55573/api/vouchers(5) [ODataRoute("({id})")] public async Task<IHttpActionResult> delete([FromODataUri]int id) { return Ok(""); } //POST : //localhost:55573/api/vouchers (body is voucher object json) public async Task<IHttpActionResult> post([FromBody]Voucher voucher) { return Ok(voucher); } //RPC---------------------------------------------------------------------------------------------------- //GET //localhost:55573/api/vouchers/RPC.getTotal() public async Task<int> getTotal() //这里可以依赖注入ODataQueryOptions | body data | params 都可以的! { return 11; } //POST //localhost:55573/api/vouchers/RPC.setTotal?paraData=5 //body : {name : "keatkeat"} public class BodyData { public string name { get; set; } }
//这里没有放[HttpPost]也是可以,但是方法名字千万不要用get开头 public async Task<int> setTotal(int paraData, BodyData bodyData) //这里可以依赖注入ODataQueryOptions | body data | params 都可以的! { return 11; } //官网的写法
[ODataRoute("({id})/RPC.updateProducts")] 如果要api/products(1)/RPC.updateProducts 就要这样写 public async Task<IHttpActionResult> setTotalTwo(int paraData, ODataActionParameters parameters) { string name = (string)parameters["name"]; //get from body 这是个字典
List<AccountRole> roles = ((IEnumerable<AccountRole>)(parameter["roles"])).ToList(); for list return Ok(11); }
Global contoller :
//开一个隔离的ctrl for Global RPC public class RPCController : ODataBaseController { //POST //localhost:55573/api/getData() 这里不需要放namspace哦 [HttpPost] //一定要放 [ODataRoute("setData")] //需要用ODataRoute 帮助 //parameter 和entity RPC 的用法是一样的 public async Task<IHttpActionResult> setData() { return Ok(11); } //GET //localhost:55573/api/getData() [HttpGet] [ODataRoute("getData")] public async Task<IHttpActionResult> getData() { return Ok(22); } }
Note : Odata 所有控制器,如果没有写上attribute [HttpPost|Get|..] 来表明它的请求方法,那么Odata会智能的用你的方法名开头来做请求方法的区分。
建议 : 1. 方法名前面都加入请求方式
2. 使用Attribute
更新 :
今天遇到一个bug, 就是如果我们没有使用上面说的官网的写法的话,parameter不可以是抽象的, 也不可以是 entity 类, 所以只可以放一些简单的对象, 可能是 odata 无法智能的从@odata.type 里创建出来。解决方法很简单就是使用官网的写法就可以了。
还有就是抽象是不能被 Validate 的
[ODataRoute("RPC.setPayment")] public async Task<IHttpActionResult> setPayment(ODataActionParameters parameters) { if (!ModelState.IsValid) //这里只是验证 parameter 类型是否正确 { } else { SetPaymentData s = (SetPaymentData)parameters["setPaymentData"]; BankTransfer payment = (BankTransfer)parameters["payment"]; Validate(s); if (!ModelState.IsValid) //这里才是验证 property { } Validate(payment); if (!ModelState.IsValid) //error 会被累加起来 { } } return Ok(); }
更新 : 2016-01-29
RPC Globar 案例
var getOrder = builder.Function("getOrder"); //简单的写 builder.Function 或 builder.Action
//return 和 normal 一样
//可以用一个 GlobalController 来装
public class GlobalController : BaseController { [ODataRoute("getOrder")] [EnableQuery(AllowedQueryOptions = Helper.ALLOW_QUERY | AllowedQueryOptions.Expand, MaxExpansionDepth = 4)] public SingleResult<Order> getOrder(string code, string token) { IQueryable<Order> order = db.Orders.Where(o => o.code == code && o.token == token); return SingleResult.Create<Order>(order); } }
builder.Function("名子") ,ODataRoute("名字") , api/"名字" 一致, 方法名就无所谓
调用的 url 是 "api/getOrder"
分类:
ASP.NET
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 百万级群聊的设计实践
· 全网最简单!3分钟用满血DeepSeek R1开发一款AI智能客服,零代码轻松接入微信、公众号、小程
· .NET 10 首个预览版发布,跨平台开发与性能全面提升
· 《HelloGitHub》第 107 期
· 从文本到图像:SSE 如何助力 AI 内容实时呈现?(Typescript篇)