Search code examples
c#azureazure-mobile-servicespatchbad-request

Azure Mobile App - UpdateAsync - waiting for activation "Error"


I have two projects

First is Mobile App with Xamarin.Forms

Second is Windows Form Application

and both have the same API that was created using Azure Mobile App.

in Windows form when I'm trying to update a row in the database with a.Net HttpClient using the following code :

private void BtnUpdateUser_Click(object sender, EventArgs e)
    {
        UserRepository userRepository = new UserRepository();
        var user = userRepository.GetAllUsers().FirstOrDefault(w => w.UserId == 1)

        user.UserName = "UpdateUserName";

        var result = userRepository.UpdateUser(user.Id, user);
    }

In UserRepository class I have a method called UpdateUser

public User UpdateUser(string id, User user)
    {
        var result = Task.Run(async () => await azureServices.UpdateAsync(id, user)).Result;
        return result;
    }

In AzureServices class I have a method called UpdateAsync

public async Task<T> UpdateAsync(string id, T instance)
    {

        var Uri= new Uri(baseAddress + id + zumoAddition); //"http://localhost:55040/tables/User/48D68C86-6EA6-4C25-AA33-223FC9A27959?zumo-api-version=2.0.0
        var content = JsonConvert.SerializeObject(instance);
        await _httpClient.PatchAsync(Uri, new StringContent(content, Encoding.UTF8, "application/json"));

        return instance;
    }

PatchAsync is an extension method to do a PATCH request with the Windows.Web.Http.HttpClient

public static async Task<HttpResponseMessage> PatchAsync(this HttpClient Client, Uri requestUri, HttpContent contnet)
    {

        var method = new HttpMethod("PATCH");
        var httpRequestMessage = new HttpRequestMessage(method, requestUri)
        {
            Content = contnet
        };

        var httpResponseMessage = new HttpResponseMessage();
        try
        {
            httpResponseMessage = await Client.SendAsync(httpRequestMessage);
        }
        catch (TaskCanceledException e)
        {
            Debug.WriteLine("Error: " + e.ToString());
        }
        return httpResponseMessage;
    }

in this line httpResponseMessage = await Client.SendAsync(httpRequestMessage); I get this error:

{StatusCode: 400, ReasonPhrase: 'Bad Request', Version: 1.1, Content: System.Net.Http.StreamContent, Headers: { x-zumo-server-version: net-2.0.0 X-SourceFiles: =?UTF-8?B?QzpcVXNlcnNcQW5hc1xEZXNrdG9wXFB1cmNoYXNlT3JkZXJzQmFja2VuZFxQdXJjaGFzZU9yZGVyc0JhY2tlbmRcdGFibGVzXFVzZXJcNTA1NzdBOTMtOEEzRi00OTEwLUJBOEYtM0MwMkMyOUFDMDUx?= Date: Thu, 29 Nov 2018 10:20:59 GMT Server: Microsoft-IIS/10.0 X-Powered-By: ASP.NET Content-Length: 188 Content-Type: application/json; charset=utf-8 }}

In the backend I have a controller with a Patch method:

public Task<User> PatchUser(string id, Delta<User> patch)
    {
         return UpdateAsync(id, patch);
    }

when I try debugging the backend I get this:

Id = 179, Status = WaitingForActivation, Method = "{null}", Result = "{Not yet computed}"

enter image description here

The question is:How I can get rid of this error and why it appears.


Solution

  • On the client side (Windows form) you are mixing async and blocking calls like .Result, which can lead to deadlocks.

    Since you are using HttpClient then you should aim to keep the code async all the way through.

    UserRepository needs to be update to allow non blocking async calls

    public Task<User> UpdateUserAsync(string id, User user) {
        return azureServices.UpdateAsync(id, user);
    }
    

    Event handlers allow for async calls so that would need to be refactored to

    private asyc void BtnUpdateUser_Click(object sender, EventArgs e) {
        UserRepository userRepository = new UserRepository();
        var user = userRepository.GetAllUsers().Where(w => w.UserId == 1).FirstOrDefault();
    
        user.UserName = "UpdateUserName";
    
        var result = await  userRepository.UpdateUserAsync(user.Id, user);
    }
    

    That should help mitigate any deadlocks that could occur on the client side.

    On the back-end the TableController action is expecting a Delta<User>, which based on what is send from the client may not be formatted correctly.

    The client is sending a plain aplication/json User as content, which may not bind correctly to Delta<User> which is expecting to handle only changes to be made to the model.