可以避免使用TableController进行乐观并发检查

时间:2016-11-14 11:45:10

标签: c# entity-framework concurrency odata azure-mobile-services

我只是通过Visual Studio使用示例ASP.NET Mobile App Web API进行测试,并对并发检查提出了一些问题。

TableController<T>要求使用以下内容提交更新:

protected virtual Task<TData> UpdateAsync(string id, Delta<TData> patch)

即。它需要Delta<T>个更改。没有&#34;覆盖&#34;更新

项目中的样本实体是TodoItem,它派生自EntityData,它实现了一堆标准属性,其中一个是Version属性,据我所知实体框架将检测作为并发属性以在更新之前检查版本。

我已经为Get TodoItem创建了一个测试客户端,更改了Text属性,然后将其作为更新提交。

我发现如果我只是发送包含更新的Text属性的Delta(当然还有URL中的Id),那么我可以根据需要更新在此期间可能发生的覆盖和更改

如果我更改了Delta,以便在我抓取时更新Text属性 Version TodoItem,那么如果我制作我的补丁请求如果在此期间发生了变化,我会收到409错误,正如预期的那样。

任何人都可以告诉我为什么这种Delta模式似乎允许你绕过并发检查,并且有没有办法确保检查总是发生?

1 个答案:

答案 0 :(得分:0)

似乎 完全可以绕过并发检查,但它基于请求标头&#34; If-Match&#34;。

请参阅https://github.com/Azure/azure-mobile-apps-net-server/blob/master/src/Microsoft.Azure.Mobile.Server.Tables/TableControllerOfData.cs#L332

byte[] version = this.Request.GetVersionFromIfMatch();
if (version != null)
{
    if (!patch.TrySetPropertyValue(TableUtils.VersionPropertyName, version))
    {
        string error = TResources.TableController_CouldNotSetVersion.FormatForUser(TableUtils.VersionPropertyName, version);
        this.traceWriter.Error(error, this.Request, ServiceLogCategories.TableControllers);
        throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.InternalServerError, error));
    }
}

所以,如果没有&#34; If-Match&#34;版本然后不进行并发检查。

如果您使用的是Azure移动应用客户端SDK,那么&#34;版本&#34;你的实体的财产被提升了#34;然后加入&#34; If-Match&#34;标题为你。见https://docs.microsoft.com/en-gb/azure/app-service-mobile/app-service-mobile-dotnet-how-to-use-client-library#optimisticconcurrency

因此,如果要强制进行并发检查,则需要确保&#34; If-Match&#34;已设定。即

// PATCH tables/TodoItem/48D68C86-6EA6-4C25-AA33-223FC9A27959
public Task<TodoItem> PatchTodoItem(string id, Delta<TodoItem> patch)
{
    CheckUpdateForPrecondition();
    return UpdateAsync(id, patch);
}

private void CheckUpdateForPrecondition()
{
    if (!Request.Headers.Contains("If-Match"))
        throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.BadRequest)
        {
            Content = new StringContent("A pre-condition version must be supplied with Update (Header: If-Match).")
        });
}