Search code examples
c#jsonxamarinhttpclientmvvmcross

Json post via httpclient mvvmcross


I have a problem sending a JSON POST via HttpClient object in a MVVMCROSS solution (Xamarin). MVVMCROSS is just a Model View ViewModel framework for cross-platform e.g. Droid, iOS, Windows etc.

So the Solution is like this:

 --Core (where I have my ViewModels and Services)
 --Droid (Android Layout etc)
 --iOS (Not used currently)

Inside the Core I have my Service classes which I initialize via IoC (Inversion of Control, something like dependency injection)

I have this awesome API which I can use via JSON Post request. The API does face recognition and sends back the 'mood' of the face (Angry, Neutral, Happy etc.)

To use this my JSON should look like this

{
    "url" : "http://previews.123rf.com/images/kadettmann/kadettmann1508/kadettmann150800099/43824672-Handsome-argentinian-guy-at-beach-Stock-Photo-happy.jpg"
}

So far so good, now the POST url is : https://api.projectoxford.ai/emotion/v1.0/recognize Seems not to hard I guess!

I also need to send two headers:

Content-Type = application/json
Ocp-Apim-Subscription-Key = My super awesome secret key

If is send this JSON via POSTMAN (Chrome plugin) I get the expected result:

[
  {
    "faceRectangle": {
      "height": 312,
      "left": 563,
      "top": 208,
      "width": 312
    },
    "scores": {
      "anger": 0.00000000112,
      "contempt": 0.000000049,
      "disgust": 0.0000000035,
      "fear": 0.000000000106,
      "happiness": 0.99999994,
      "neutral": 0.000000000238,
      "sadness": 0.00000000005,
      "surprise": 0.00000000160
    }
  }
]

So now i'm trying to make a MVVMCROSS app for Android and iOS which sends this JSON to the server of Microsoft.

The method I use looks like this:

public async Task<bool> RestRequestSucces(string secret, string jsonSerialized)
{
    bool result = false;    

    try
    {
        HttpResponseMessage response;

        using (var httpClient = new HttpClient())
        {
            var request = new StringContent(jsonSerialized);
            request.Headers.ContentType = new MediaTypeHeaderValue("application/json");

            httpClient.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", secret);

            response = await httpClient.PostAsync(new Uri("https://api.projectoxford.ai/emotion/v1.0/recognize"), request);

            result = true;
        }
    }
    catch (Exception e)
    {
        string error = e.Message;
        result = false;
    }
    return result;
}

The JsonObject to serialized looks like this:

public class URLObject
{
    public string url { get; set; }
}

To serialize the object I use this

private IMvxJsonConverter serializer = Mvx.Resolve<IMvxJsonConverter>();
serializer.SerializeObject(urlObject);

But at response = await httpClient.PostAsync my code hangs. It does not go any furthur.

I call the method RestRequestSucces like this:

IRestService restService = Mvx.Resolve<IRestService>();
restService.RestRequestSucces(secret, jsonSerialized);

This all happens inside the Core project.

My AndroidManifest.xml looks like this:

...
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <application android:label="@string/ApplicationName" android:icon="@drawable/Icon" android:theme="@style/MyTheme"></application>
</manifest>

If someone could show me how to just POST a 'simple' JSON via MVVMCROSS inside the CORE project, that would be awesome!!


Solution

  • Solved it myself,

    Turns out HttpClient has trouble with some TLS/SSL website (https). By just using the ModernHttpClient solved my issue!

    The rest of the code remains the same, only the HttpClient constructor is different

    using (var httpClient = new HttpClient(new NativeMessageHandler()))
    {
        ....
    }
    

    The NativeMessageHandler is a HttpClientHandler and can be found in the ModernHttpClient, the code looks like this:

    namespace ModernHttpClient
    {
        public class NativeMessageHandler : HttpClientHandler
        {
            public NativeMessageHandler();
            public NativeMessageHandler(bool throwOnCaptiveNetwork, bool customSSLVerification, NativeCookieHandler cookieHandler = null);
    
            public bool DisableCaching { get; set; }
    
            public void RegisterForProgress(HttpRequestMessage request, ProgressDelegate callback);
            [AsyncStateMachine(typeof(<SendAsync>c__async0))]
            [DebuggerStepThrough]
            protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken);
        }
    }
    

    Hope you guys can use this! Link to ModernHttpClient on github.