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" 

 

posted @ 2015-04-18 22:31  兴杰  阅读(543)  评论(0)    收藏  举报