Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

[SOLVED] UnityWebRequest POST does not post data to body

Discussion in 'Scripting' started by GuiiDo, Dec 25, 2018.

  1. GuiiDo

    GuiiDo

    Joined:
    Dec 24, 2018
    Posts:
    5
    Hi, i am currently new to Unity and i'm trying to make a simple menu where a user needs to login to continue.
    I have all the UI stuff working and i can access it in my C# script.

    But now comes the issue, i have a .NET core 2.0 API that has an endpoint that looks like this.
    Code (CSharp):
    1. [HttpPost, Route("[controller]/login"), AllowAnonymous]
    2.         public IActionResult Login([FromBody] LoginUserDto userDto)
    3.         {
    4.             if (!ModelState.IsValid) return BadRequest("Model not valid");
    5.  
    6.             var user = service.Authenticate(userDto.Username, userDto.Password);
    7.  
    8.             if (user == null) return BadRequest("Username or password incorrect");
    9.  
    10.          // Generating JWT Token here
    11.  
    12.             return Ok(new
    13.             {
    14.                 Token = tokenString
    15.             });
    16.         }
    And my code in my Unity script looks as following.

    Code (CSharp):
    1. public class LoginMananger : MonoBehaviour {
    2.  
    3.     public InputField username;
    4.     public InputField password;
    5.  
    6.     public void Login()
    7.     {
    8.         StartCoroutine(Post());
    9.     }
    10.  
    11.     IEnumerator Post()
    12.     {
    13.         var user = new User
    14.         {
    15.             Username = username.text,
    16.             Password = password.text
    17.         };
    18.  
    19.         var body = JsonUtility.ToJson(user);
    20.  
    21.         UnityWebRequest request = UnityWebRequest.Post("http://localhost:5000/user/login", body);
    22.         request.SetRequestHeader("content-Type", "application/json");
    23.         request.SetRequestHeader("Accept", "application/json");
    24.         request.SetRequestHeader("api-version", "0.1");
    25.  
    26.         yield return request.SendWebRequest();
    27.  
    28.         if (request.isNetworkError || request.isHttpError) Debug.Log(request.error);
    29.  
    30.         Debug.Log($"Response as byte: {request.downloadHandler.data}");
    31.         Debug.Log($"Response as string: {request.downloadHandler.text}");
    32.     }
    33. }
    When i debug both my Unity script and my API, the API says that my loginUserDto object is null.
    Any help would be greatly appreciated!

    Edit: The User and UserLoginDto classes are identical, so that is not the problem.
     
    Meltdown likes this.
  2. Lurking-Ninja

    Lurking-Ninja

    Joined:
    Jan 20, 2015
    Posts:
    9,904
  3. GuiiDo

    GuiiDo

    Joined:
    Dec 24, 2018
    Posts:
    5
    Tried this, but same thing as before, userDto object is still null.
    To add to this issue, when i call the API from Postman i get the behavior i want.
     
  4. Lurking-Ninja

    Lurking-Ninja

    Joined:
    Jan 20, 2015
    Posts:
    9,904
    Are you sure your webserver is configured properly? Can you call it from a browser? Unfortunately I can't tell anything about your action implementation I have no web.net expertise... If it were Java or PHP or even Python or Perl, I could at least guess, but not with .net.
     
  5. GuiiDo

    GuiiDo

    Joined:
    Dec 24, 2018
    Posts:
    5
    As far as i know it is, Postman can make calls to my API and there the object is the actual object that i expect to get.
    However i can not test this in browser because the API requires headers for API version.
     
    chavantfou likes this.
  6. GuiiDo

    GuiiDo

    Joined:
    Dec 24, 2018
    Posts:
    5
  7. jdnichollsc

    jdnichollsc

    Joined:
    Sep 23, 2017
    Posts:
    9
    Check this library if you want to improve your code by using Promises instead of Coroutines, also you can set global headers and paramaters for all your requests => https://github.com/proyecto26/RestClient
     
  8. Raistlin2015

    Raistlin2015

    Joined:
    Apr 4, 2015
    Posts:
    27
    I am having a heck of a time wrapping my head around this concept. The Unity docs show this

    Code (CSharp):
    1. using UnityEngine.Networking;
    2. using System.Security.Cryptography.X509Certificates;
    3.  
    4. // Based on https://www.owasp.org/index.php/Certificate_and_Public_Key_Pinning#.Net
    5. class RequestCertificate: CertificateHandler
    6. {
    7.     // Encoded RSAPublicKey
    8.     private static string PUB_KEY = "30818902818100C4A06B7B52F8D17DC1CCB47362" +
    9.         "C64AB799AAE19E245A7559E9CEEC7D8AA4DF07CB0B21FDFD763C63A313A668FE9D764E" +
    10.         "D913C51A676788DB62AF624F422C2F112C1316922AA5D37823CD9F43D1FC54513D14B2" +
    11.         "9E36991F08A042C42EAAEEE5FE8E2CB10167174A359CEBF6FACC2C9CA933AD403137EE" +
    12.         "2C3F4CBED9460129C72B0203010001";
    13.  
    14.     protected override bool ValidateCertificate(byte[] certificateData)
    15.     {
    16.         X509Certificate2 certificate = new X509Certificate2(certificateData);
    17.         string pk = certificate.GetPublicKeyString();
    18.         if (pk.Equals(PUB_KEY))
    19.             return true;
    20.  
    21.         // Bad dog
    22.         return false;
    23.     }
    24. }

    I am using a node / express server with a Letsencrypt certificate.

    I tried ```UnityWebRequest``` first.

    Code (CSharp):
    1.     protected IEnumerator Register()
    2.     {
    3.         List<IMultipartFormSection> wwwForm = new List<IMultipartFormSection>();
    4.         wwwForm.Add(new MultipartFormDataSection("name", uName.text));
    5.         wwwForm.Add(new MultipartFormDataSection("email", uEmail.text));
    6.         wwwForm.Add(new MultipartFormDataSection("screenName", uScreenName.text));
    7.         wwwForm.Add(new MultipartFormDataSection("password", uConPass.text));
    8.  
    9.         UnityWebRequest www = UnityWebRequest.Post(US_GameManager.API_URL + "users/store-user", wwwForm);
    10.         www.certificateHandler = new RequestCertificate();
    11.         Debug.Log(www.certificateHandler);
    12.         yield return www.SendWebRequest();
    13.  
    14.         if (www.isNetworkError || www.isHttpError)
    15.         {
    16.             debugText.text += " Error: " + www.error;
    17.         }
    18.         else
    19.         {
    20.  
    21.         }
    22.     }
    I get
    Code (CSharp):
    1. Mono.Security.Interface.TlsException: Handshake failed - error code: UNITYTLS_INTERNAL_ERROR, verify result: UNITYTLS_X509VERIFY_NOT_DONE
    2.  
    Then I tried:

    Code (CSharp):
    1.     public void SendRegisterRequest(string endPoint, RegistrationRequestBody playerData)
    2.     {
    3.         var http = (HttpWebRequest)WebRequest.Create(US_GameManager.API_URL + endPoint);
    4.         http.ContentType = "application/json";
    5.         http.Method = "POST";
    6.         string l_result = string.Empty;
    7.  
    8.         using (var streamWriter = new StreamWriter(http.GetRequestStream()))
    9.         {
    10.             string reqBody = JsonConvert.SerializeObject(playerData);
    11.             streamWriter.Write(reqBody);
    12.             streamWriter.Flush();
    13.             streamWriter.Close();
    14.  
    15.             var response = (HttpWebResponse)http.GetResponse();
    16.  
    17.             using (var streamReader = new StreamReader(response.GetResponseStream()))
    18.             {
    19.                 l_result = streamReader.ReadToEnd();
    20.                 debugText.text += $"SendRegisterRequest() {l_result} \n";
    21.             }
    22.         }
    23.  
    24.         m_regRes = (RegistrationResponseBody)DSRegistraionResponse(l_result);
    25.  
    26.         debugText.text += $" m_regRes: {m_regRes} route: {US_GameManager.API_URL }{m_endPoint} \n";
    27.  
    28.         Debug.Log("Reg Res: " + m_regRes.Message);
    29.         // response body status == 200
    30.         if (m_regRes.Status == 200)
    31.         {
    32.             sceneManager.SetUserId(m_regRes.userId);
    33.             print("RES userId: " + m_regRes.userId);
    34.             debugText.text += $" m_regRes: {m_regRes} route: {m_endPoint} \n";
    35.             Player.name = m_regRes.name;
    36.             Player.userId = m_regRes.userId;
    37.             Player.screenName = m_regRes.screenName;
    38.             Player.scores = m_regRes.scores;
    39.             Player.lastScenePlayed = m_regRes.lastScenePlayed;
    40.             Player.friendsList = m_regRes.friendsList;
    41.             Player.isLoggedIn = true;
    42.             PlayerPrefs.SetString("userID", m_regRes.userId);
    43.             //sceneManager.LoadScene(2); // Registration successful => load lobby
    44.         }
    45.     }
    46.  
    With the same result. One thing that throws me is when is
    Code (CSharp):
    1. ValidateCertificate()
    being called? I cant call it from my registration script because it's protected.
    Any and all help is greatly appreciated.
     
  9. Aurimas-Cernius

    Aurimas-Cernius

    Unity Technologies

    Joined:
    Jul 31, 2013
    Posts:
    3,637
    ValidateCertificate is called by UnityWebRequest itself. There are few additional conditions:
    - the request has to HTTPS (obviously)
    - all TLS stuff must be correct until you get to the point of deciding whether certificate is trusted or not
     
    Raistlin2015 likes this.
  10. Raistlin2015

    Raistlin2015

    Joined:
    Apr 4, 2015
    Posts:
    27
    I really appreciate the help. Does LetsEncrypt generated by CertBot cause the failure?