zoukankan      html  css  js  c++  java
  • web api 2 学习笔记 (OData Batch request)

    之前介绍过OData 中实现RPC的写法,今天在来一个批量操作。

    参考 : https://damienbod.wordpress.com/2014/08/14/web-api-odata-v4-batching-part-10/

    http://www.odata.org/getting-started/advanced-tutorial/

    public static void Register(HttpConfiguration config)
    {
        DefaultODataBatchHandler odataBatchHandler = new DefaultODataBatchHandler(GlobalConfiguration.DefaultServer);
        odataBatchHandler.MessageQuotas.MaxOperationsPerChangeset = 10;
        odataBatchHandler.MessageQuotas.MaxPartsPerBatch = 10;
        config.MapODataServiceRoute("odata", "api", GetModel(), odataBatchHandler);           
    }

    填入DefaultODataBatchHandler就可以了.

    前端js

    var xhr = new XMLHttpRequest();
    xhr.open("POST", "http://localhost:4274/api/$batch", true);
    xhr.setRequestHeader("Content-Type", "multipart/mixed; boundary=batch_ebdc0b88-eeb1-4dd6-b170-74331f39bd03");
    xhr.setRequestHeader("OData-Version", "4.0");
    xhr.setRequestHeader("singleTransaction", "true");
    
    var body = [];
    //POST
    body.push('--batch_ebdc0b88-eeb1-4dd6-b170-74331f39bd03');
    body.push('Content-Type: multipart/mixed; boundary=changeset_54ac09ec-f437-4b08-9925-fd42ed7bd58f');
    body.push('');
    body.push('--changeset_54ac09ec-f437-4b08-9925-fd42ed7bd58f');
    body.push('Content-Type: application/http');
    body.push('Content-Transfer-Encoding: binary');
    body.push('Content-ID: 1');
    body.push('');
    body.push('POST http://localhost:4274/api/products HTTP/1.1');
    body.push('OData-Version: 4.0');
    body.push('Content-Type: application/json;odata.metadata=minimal');
    body.push('Accept: application/json;odata.metadata=minimal');
    body.push('');
    body.push('{"code":"mk100"}');
    body.push('--changeset_54ac09ec-f437-4b08-9925-fd42ed7bd58f--');
    
    //PUT
    body.push('--batch_ebdc0b88-eeb1-4dd6-b170-74331f39bd03');
    body.push('Content-Type: multipart/mixed; boundary=changeset_2346da5e-88c9-4aa5-a837-5db7e1368147');
    body.push('');
    body.push('--changeset_2346da5e-88c9-4aa5-a837-5db7e1368147');
    body.push('Content-Type: application/http');
    body.push('Content-Transfer-Encoding: binary');
    body.push('Content-ID: 2');
    body.push('');
    body.push('PUT http://localhost:4274/api/products(1) HTTP/1.1');
    body.push('OData-Version: 4.0');
    body.push('Content-Type: application/json;odata.metadata=minimal');
    body.push('Accept: application/json;odata.metadata=minimal');
    body.push('');
    body.push('{"id":1,"code":"mk100"}');
    body.push('--changeset_2346da5e-88c9-4aa5-a837-5db7e1368147--');
    
    
    //DELETE
    body.push('--batch_ebdc0b88-eeb1-4dd6-b170-74331f39bd03');
    body.push('Content-Type: multipart/mixed; boundary=changeset_2346da5e-88c9-4aa5-a837-5db7e1368142');
    body.push('');
    body.push('--changeset_2346da5e-88c9-4aa5-a837-5db7e1368142');
    body.push('Content-Type: application/http');
    body.push('Content-Transfer-Encoding: binary');
    body.push('Content-ID: 3');
    body.push('');
    body.push('DELETE http://localhost:4274/api/products(1) HTTP/1.1');
    body.push('OData-Version: 4.0');
    body.push('Content-Type: application/json;odata.metadata=minimal');
    body.push('Accept: application/json;odata.metadata=minimal');
    body.push('');
    body.push('--changeset_2346da5e-88c9-4aa5-a837-5db7e1368142--');
                
    //GET
    body.push('--batch_ebdc0b88-eeb1-4dd6-b170-74331f39bd03');
    body.push('Content-Type: application/http');
    body.push('Content-Transfer-Encoding: binary');
    body.push('Content-ID: 4');
    body.push('');
    body.push('GET http://localhost:4274/api/products HTTP/1.1');
    body.push('OData-Version: 4.0');
    body.push('Content-Type: application/json;odata.metadata=minimal');
    body.push('Accept: application/json;odata.metadata=minimal');
    body.push('');
    
    body.push('--batch_ebdc0b88-eeb1-4dd6-b170-74331f39bd03--');
    body.push('');
    var data = body.join("
    ");
    xhr.send(data);

    从上面代码可以看出,我们所有的请求需要通过一个大请求来包装,把所有的小请求用string写进大请求的body就可以了。

    需要特别注意的事string的格式,连空行都是非常重要的哦!

    参考 http://www.odata.org/documentation/odata-version-3-0/batch-processing/

    虽然这是v3的但是可以看一下, 2.2 Batch Request Body 

    请求分2中,一种叫changeset,一种叫 operation 

    changeset 是指那些会改变资源的请求(e.g. POST,PUT,DELETE,ACTION), operation 是指不会改变资源的请求 (e.g. GET,FUNCTION) 

    代码中可以看出来,这2种写法会有不同。

    通常我们在做批量操作时希望会有transaction

    这时我们可以扩展 DefaulODataBatchHandle 

    public class ODataBatchHandlerSingleTransaction : DefaultODataBatchHandler
    {
        public ODataBatchHandlerSingleTransaction(HttpServer httpServer)
            : base(httpServer)
        {
        }
    
        public async override Task<IList<ODataBatchResponseItem>> ExecuteRequestMessagesAsync(IEnumerable<ODataBatchRequestItem> requests,CancellationToken cancellation)
        {
            if (requests == null) { throw new ArgumentNullException("requests"); }            
            IList<ODataBatchResponseItem> responses = new List<ODataBatchResponseItem>();
                             
            try
            {
                using (DB db = new DB())
                {
                    using (DbContextTransaction trans = db.Database.BeginTransaction())
                    {
                        foreach (ODataBatchRequestItem request in requests)
                        {
                            var changeSetResponse = (ChangeSetResponseItem)await request.SendRequestAsync(Invoker, cancellation);
                            responses.Add(changeSetResponse);
                        }
                        bool isAllOk = responses.All(response => ((ChangeSetResponseItem)(response)).Responses.All(r => r.IsSuccessStatusCode));
                        if (isAllOk)
                        {
                            trans.Commit();
                        }
                        else
                        {
                            trans.Rollback();
                        }
                    }
                }
            }
            catch
            {
                foreach (ODataBatchResponseItem response in responses)
                {
                    if (response != null)
                    {
                        response.Dispose();
                    }
                }
                throw;
            }
            return responses;
        }      
    } 

    拦截以后我们就可以在这一层创建 database Context 和 transaction , controller 内就可以通过任何方式来获取到这里的 context 来做使用. 

    比如可以使用 Request.Items 来保存传值. (注 : httpRequest 和 httpRequestMessage 是不同的,我们在controller使用的是 message 哦)  

    还有一点要特别注意的是,如果你需要transaction就不应该有请求,因为GET 请求会在 ExecuteRequestMessagesAsync 之后才执行,如果这时我们释放掉了 database context 那么就会有问题了.

  • 相关阅读:
    修复PLSQL Developer 与 Office 2010的集成导出Excel 功能
    Using svn in CLI with Batch
    mysql 备份数据库 mysqldump
    Red Hat 5.8 CentOS 6.5 共用 输入法
    HP 4411s Install Red Hat Enterprise Linux 5.8) Wireless Driver
    变更RHEL(Red Hat Enterprise Linux 5.8)更新源使之自动更新
    RedHat 5.6 问题简记
    Weblogic 9.2和10.3 改密码 一站完成
    ExtJS Tab里放Grid高度自适应问题,官方Perfect方案。
    文件和目录之utime函数
  • 原文地址:https://www.cnblogs.com/keatkeat/p/4806324.html
Copyright © 2011-2022 走看看