web-dev-qa-db-fra.com

RestSharp "Erreur lors de l'obtention du flux de réponse (ReadAsync): ReceiveFailure La valeur ne peut pas être null. Nom du paramètre: src"

Bonjour à tous, j'essaie de me connecter à mon api xamarin avec RestSharp. L’API doit renvoyer le code d’état 200 OK si l’authentification fonctionne et le code d’état 415 si l’authentification échoue (mot de passe incorrect) et d’autres codes, en fonction du cas de figure, mais au lieu de cela, je reçois un code d’état 0 sur tous les autres cas en dehors de l’authentification (code d’état 200 ok), le code source ci-dessous est la façon dont j’implémente

 //payload am sending to the api
   RequestPayload res = new RequestPayload();
   res.appid = appid;
   res.data = data;
   res.method = "Login";

   //convert to json object
   var MySerializedObject =  JsonConvert.SerializeObject(res);
   string APIUrl = ""http://142.168.20.15:8021/RouteTask";

   //create client
   RestClient client = new RestClient(APIUrl);

   //create request
   RestRequest request = new RestRequest(Method.POST);

   // set request headeer
   request.AddHeader("Content-Type", "application/x-www-form-urlencoded");

   //request.AddJsonBody(MySerializedObject); --i have also tried this

   request.AddParameter("application/json", MySerializedObject, ParameterType.RequestBody);
   request.JsonSerializer.ContentType = "application/json; charset=utf-8";
   request.AddParameter("RequestSource", "Web", "application/json", ParameterType.QueryString);
   client.Timeout = 2000000;
   var response =  client.Execute(request); // where the issue appears
   //RestResponse response =  client.Execute(request); // i have tried this
   //IRestResponse response =  client.Execute(request); // i have tried this
    if (response.IsSuccessful)
        {
         //use response data
        }

sur tous les scenerio il revient avec StatusCode: 0, Content-Type:, Content-Length: 0) et errorMessage 

"Erreur lors de l'obtention du flux de réponse (ReadAsync): ReceiveFailure Value Ne peut pas être null. Nom du paramètre: src"

la capture d'écran ci-dessous indique quand l'appel d'API échoue  enter image description here Réponse reçue lorsque l'authentification est valide  Success Authentication

3
olufemi jolugbo

J'ai finalement réussi à trouver une solution de contournement. Ours avec la réponse longue.

Les balises mentionnent Xamarin, ce sur quoi je travaille également, en particulier avec iOS. Je pense que c'est peut-être un problème avec Mono, mais je ne l'ai pas poussé aussi loin pour le confirmer. 

Le problème réside dans la méthode par défaut de copie du tampon de réponse. Dans le code RestSharp, cela est effectué par une méthode d'extension dans MiscExtensions.cs appelée ReadAsBytes. Il semble qu'avec certains tampons de réponse, l'appel de la méthode Stream.Read échoue. Lorsque cela se produit, l'exception force RestSharp à "raccourcir" le reste du traitement de la réponse. Par conséquent, le code de statut n'est jamais renseigné puisqu'il se produit après l'appel de ReadAsBytes.

La bonne nouvelle est que RestSharp donne le moyen de remplacer cet appel à ReadAsBytes par l’un des vôtres. Cela se fait via la propriété ResponseWriter sur l'objet IRestRequest. Si une fonction est définie, elle ignore l'appel ReadAsBytes et appelle la fonction que vous lui avez donnée. Le problème est que ceci est défini comme une action et que vous n'obtenez pas une copie de l'objet de réponse complet, c'est donc un peu inutile. Au lieu de cela, vous devez utiliser la propriété AdvancedResponseWriter. Celui-ci inclut à la fois l'objet de réponse et le flux de réponse. Mais vous devez toujours définir la propriété ResponseWriter ou elle ne contournera pas le gestionnaire par défaut et vous obtiendrez toujours l'erreur.

Ok, alors comment faites-vous ce travail? J'ai fini par l'implémenter comme un wrapper pour RestClient afin de ne pas avoir à implémenter le code partout. Voici la configuration de base:

public class MyRestClient : RestClient
{
    public MyRestClient(string baseUrl) : base(baseUrl)
    { }

    public override IRestResponse Execute(IRestRequest request)
    {
        request.ResponseWriter = s => { };
        request.AdvancedResponseWriter = (input, response) => response.RawBytes = ReadAsBytes(input);

        return base.Execute(request);
    }

    private static byte[] ReadAsBytes(Stream input)
    {
        var buffer = new byte[16 * 1024];

        using (var ms = new MemoryStream())
        {
            int read;
            try
            {
                while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
                { ms.Write(buffer, 0, read); }

                return ms.ToArray();
            }
            catch (WebException ex)
            { return Encoding.UTF8.GetBytes(ex.Message); }
        };
    }
}

La méthode ReadAsBytes est en réalité juste un copier/coller de la méthode RestSharp ReadAsBytes avec l’ajout d’un try/catch. S'il échoue, il renvoie le motif de l'exception dans le tampon de réponse. Cela peut être ou ne pas être ce que vous voulez, alors modifiez-le si nécessaire. Vous devrez peut-être aussi remplacer d'autres méthodes pour Execute, mais dans mon cas, c'est la seule que nous utilisons, donc c'était suffisant.

Jusqu'à présent, cela semble faire l'affaire pour moi. Peut-être que si quelqu'un devenait ambitieux, il pourrait aller jusqu'à Mono pour essayer de voir ce qu'il n'aime pas dans le flux, mais je n'ai pas le temps de le faire.

Bonne chance!

4
Steve In CO

OK, donc après avoir passé un peu de temps avec RestSharp, je me rends compte que @steve_In_Co a mentionné plus tôt qu'il y avait des problèmes de compatibilité avec MONO (nous supposons qu'il s'agit d'un bogue), donc je l'ai fait de manière basique en utilisant la bibliothèque HTTP .Net et cela fonctionne Pour moi, si quelqu'un cherche toujours un moyen de sortir, trouvez le code d'implémentation http .net actif ci-dessous.

//payload am sending to the api 
   RequestPayload res = new RequestPayload();
   res.appid = appid;
   res.data = data;
   res.method = "Login";

   //convert to json object
   var MySerializedObject =  JsonConvert.SerializeObject(res);

   string APIUrl = ""http://142.168.20.15:8021/RouteTask";

   //create basic .net http client
   HttpClient client = new HttpClient();
   client.BaseAddress = new Uri(APIUrl);

   // this was required in the header of my request, 
   // you may not need this, or you may need to adjust parameter
   //("RequestSource","Web") or you own custom headers
   client.DefaultRequestHeaders.Add("RequestSource", "Web");
    // this class is custom, you can leave it out
   connectionService = new ConnectionService();
  //check for internet connection on users device before making the call
  if (connectionService.IsConnected)
    {
       //make the call to the api
        HttpResponseMessage response = await 
        client.PostAsJsonAsync(ApiConstants.APIDefault, res);
        if (response.IsSuccessStatusCode)
            {
                string o = response.Content.ReadAsStringAsync().Result;
                dynamic payload = JsonConvert.DeserializeObject(o);
                string msg = payload["valMessage"];
                resp.a = true;
                resp.msg = payload["responseDescription"];
            }
        else
            {
                string o = response.Content.ReadAsStringAsync().Result;
                dynamic payload = JsonConvert.DeserializeObject(o);
                resp.a = false;
                resp.msg = payload["response"];
            }
    }
0
olufemi jolugbo