0
votes

I'm just testing with the sample ASP.NET Mobile App Web API through Visual Studio and have some questions regarding the concurrency checks.

The TableController<T> requires updates to be submitted using the following:

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

i.e. it takes a Delta<T> of the changes. There is no "overwrite" update.

The sample entity in the project is TodoItem which derives from EntityData which implements a bunch of standard properties, one of which is the Version property, which as I understand Entity Framework will detect as the concurrency property to check versions before update.

I've created a test client to Get a TodoItem, change the Text property and then submit it as an update.

I have found that if I just send the the Delta containing the updated Text property (along with the Id in the URL, of course) then I can just update as much as I want and overwrite and changes that may have occurred in the meantime.

If I change the Delta to include the updated Text property and the Version of the TodoItem when I fetched it, then if I make my Patch request I get a 409 error if there have been changes in the meantime, as expected.

Can anyone tell me why this Delta pattern seems to allow you to circumvent the concurrency checks, and if there is any way to ensure that the checks always happen?

1
You need to follow this stackoverflow.com/help/mcveCallum Linington
And how would it perform concurrency check without knowing version? Concurrency check basically goes like this: "update Something set SomeColumn = X where Version = @VersionYouHaveOnClient"Evk
@CallumLinington It's just using the out-of-the-box sample with Visual Studio - Azure SDK 2.9 > New Project > Web > ASP.NET Web App > Azure Mobile App. You can then send requests through any REST client.oatsoda
@Evk that's kind of my point - it seems to me that the Delta and the EF Concurrency checks are not really compatible as by simply omitting the Version from the Delta you can circumvent them!oatsoda
But it is not some security check, it is for client's own convenience. So you, as a developer, should not omit Version if you want optimistic concurrency. Seems no problem here.Evk

1 Answers

0
votes

It appears that it is perfectly possible to circumvent the concurrency checks, but it is based upon the Request Header "If-Match".

See 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));
    }
}

So if there is no "If-Match" Version then the concurrency checks do not take place.

If you are using the Azure Mobile App Client SDK then the "Version" property of your entity is "raised up" and put in the "If-Match" header for you. See https://docs.microsoft.com/en-gb/azure/app-service-mobile/app-service-mobile-dotnet-how-to-use-client-library#optimisticconcurrency

So if you want to force the concurrency checks, you need to ensure that "If-Match" is set. i.e.

// 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).")
        });
}