繁体   English   中英

乐观并发处理-Asp.Net WebApi Odata V4

[英]Optimistic Concurrency Handling - Asp.Net WebApi Odata V4

这是我的OdataControllerPatch方法

public async Task<IHttpActionResult> Patch([FromODataUri] int key, Delta<Product> patch)
{
   Validate(patch.GetInstance());
   Product product = await service.Products.GetAsync(key);
   if (product == null)
       return NotFound();

   patch.Put(product);

   try
   {
       await service.Products.UpdateAsync(product);
   }
   catch (DbUpdateConcurrencyException)
   {
       if (!await service.Products.ExistAsync(key))
           return NotFound();
       else
           throw;
   }

   return Updated(product);
}

我的模型有一个属性:

[Timestamp]
 public byte[] RowVersion { get; set; }

DbUpdateConcurrencyException似乎根本不起作用。 我需要使用Etag实现并发检查机制。 我在这里看到了一些示例。但是他们没有在其中使用Delta方法。

  1. 如何使用etag检查并发性?
  2. 是否可以实现用于并发检查的自定义属性?

就像是:

[CustomConcurrencyCheck]
public async Task<IHttpActionResult> Put([FromODataUri] int key, Delta<Product> patch)
{
...
}

提供一个简单的例子将受到高度赞赏。

首先,在WebApiConfig在创建模型时,必须指定哪种属性是ETag,在这种情况下:

var builder = new ODataConventionModelBuilder();
builder.EntityType<Product>()
    .Property(p => p.RowVersion)
    .IsConcurrencyToken();

稍后,您可以从控制器中Patch方法的ODataQueryOptions<T>参数检索ETag:

[AcceptVerbs("PATCH", "MERGE")]
public IHttpActionResult Patch([FromODataUri] int key, Delta<Product> delta, ODataQueryOptions<Product> options) {
    var existingEntity = //Code to get existing entity by ID, 404 if not found

    byte[] requestETag = options.IfMatch["RowVersion"] as byte[];
    if(!requestETag.SequanceEqual(existingEntity.RowVersion)) { //Simplified if-statement, also do null-checks and such
        // ETags don't match, return HTTP 412
        return StatusCode(HttpStatusCode.PreconditionFailed);
    } else {
        // The ETags match, implement code here to update your entity
        // You can use the 'Delta<Product> delta' parameter to get the changes and use the 'Validate' function here
        // ...

这是我使用的解决方案,它是一项简单的检查,以查看请求更新的客户端是否具有该服务具有的对象的相同版本。 我的解决方案的一个显着缺点是,我必须从数据库中检索现有对象才能使其正常工作,这会降低性能。

这是If-Match头的代码, ODataQueryOptions<T>也具有.IfNoneMatch[VersionColumnName]可用。 您可以在Get方法中使用它。 如果If-None-Match标头等于您的RowVersion ,则可以返回HTTP 304 (Not modified)并节省一些带宽。

如果您要实现自己的自定义属性,这是一个非常简单的示例。 至少,我会将其中一些逻辑移到辅助类中,以便可以重用。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM