Search Unity

2019.2: UnityWebRequest GET not working in UWP (HoloLens/PC) but System.Net.WebRequest does

Discussion in 'Windows' started by avikom, Nov 20, 2019.

  1. avikom

    avikom

    Joined:
    Jun 18, 2019
    Posts:
    7
    I set up a minimal Unity project with only one empty GameObject and the following script attached:

    Code (CSharp):
    1. using System.Net;
    2. using UnityEngine;
    3. using UnityEngine.Networking;
    4.  
    5. public class WebRequest : MonoBehaviour
    6. {
    7.     // Start is called before the first frame update
    8.     public string serverUrl;  // some.local.network.ip:port
    9.     void Start()
    10.     {
    11.         Debug.Log("Sending request to" + serverUrl);
    12.         UnityWebRequest getRequest = new UnityWebRequest(serverUrl, UnityWebRequest.kHttpVerbGET);
    13.         getRequest.chunkedTransfer = false;
    14.         getRequest.SendWebRequest();
    15.     }
    16. }
    I tested the code above with a local NodeJS server and successfully received requests when running a) the code in the (local) Editor and b) a built exported to an Android device and c) a build app in the HoloLens (1) emulator and d) running the app locally (APPX export as well as directly from Visual Studio). When exporting the same code to a UWP application (with Windows Mixed Reality enabled for HoloLens), the request is not received a) on a HoloLens device as well as b) a remote PC using an APPX export. On both systems -- HoloLens and remote PC -- Firefox and/or Edge were able to reach the server. I enabled EnterpriseAuthentication, InternetClient, InternetClientServer, PrivateNetworkClientServer (and WebCam, Microphone and SpatialPerception for HoloLens). I however receive some proxy errors:

    (Filename: C:\buildslave\unity\build\Modules/UnityWebRequest/Implementations/TransportCurl.cpp Line: 734)

    Curl error 7: Failed to connect to proxy.<url>.net port 1080: Connection refused


    I assume that the institute network is some influential factor here. However, the Android request worked anyway and also replacing the `UnityWebRequest` with:

    Code (CSharp):
    1.     System.Net.WebRequest request = System.Net.WebRequest.Create(serverUrl);
    2.     request.Credentials = CredentialCache.DefaultCredentials;
    3.     WebResponse response = request.GetResponse();
    allows the UWP application to reach the remote NodeJS server. I found related issues here and here but unfortunately neither updating Unity nor using trailing backslashes or chunkedTransfer solved it for me.
    I could however work around the issue by disabling "Automatically detect settings" in the Proxy section of Windows' Settings.

    Tested Unity Version: 2019.2.11f1 and 2019.2.10f1
    HoloLens Version: 17763.806.x86fre.rs5_release_svc_prod1.191005-1655
    Windows Version: Windows 10 1909

    Any suggestion about how to get UnityWebRequest working for UWP applications in a network with an HTTP proxy without the need of tinkering with the OS would be much appreciated.
     
  2. Aurimas-Cernius

    Aurimas-Cernius

    Unity Technologies

    Joined:
    Jul 31, 2013
    Posts:
    3,735
    On UWP under the hood UnityWebRequest uses this class to get proxy configuration:
    https://docs.microsoft.com/en-us/uw...networkinformation.getproxyconfigurationasync

    On Android it works, because proxies are not supported there, hence direct connection.
    It might be a bug that we don't check whether we can connect directly (ProxyConfiguration has such property).

    This documentation has more details about proxies and might explain why .NET APIs work:
    https://docs.microsoft.com/en-us/uwp/api/windows.networking.sockets.streamsocket

    Also worth to check proxy settings on device itself.
     
  3. timke

    timke

    Joined:
    Nov 30, 2017
    Posts:
    408
    Ultimately the problem is with UWP itself and the limitations imposed on the APIs.

    The NetworkInformation.GetPRoxyConfigurationAsync() API doesn't return all of the Proxy configuration data, compared to the Win32 API WinHttpGetIEProxyConfigForCurrentUser(). Instead, the WinRT APIs will automatically "plumb the connection" for you via StreamSocket, or in your case .NET WebRequest.

    Unity uses libCurl internally for HTTP instead of native APIs for better cross-platform support, but this requires us to collect proxy information from Windows and manually configure libCurl accordingly. Since Windows proxy configuration is complex, this is difficult to do even on WindowsStandalone, but it's impossible to properly support on UWP because of the restrictions imposed on the platform.

    So, unfortunately to use UnityWebRequest you'll have to manually configure HoloLens proxy settings so it'll work, or replace it with System.Net.WebRequest.
     
  4. joseGuate97

    joseGuate97

    Joined:
    Mar 1, 2018
    Posts:
    57
    This is not a very satisfying response, I have to say. Is there a way I can do it from the code? Or do I have to instruct my users on how to configure proxy settings? I'm also somewhat unfamiliar on this topic, how exactly do you configure such settings?
     
  5. joseGuate97

    joseGuate97

    Joined:
    Mar 1, 2018
    Posts:
    57
    Should we even use UnityWebRequests these days? It feels like System.Net.WebRequest is the way to go now. What's the point of an http API in Unity if it doesn't work everywhere. It's really frustrating.
     
    waltran likes this.
  6. joseGuate97

    joseGuate97

    Joined:
    Mar 1, 2018
    Posts:
    57

    I can't get it working. How do you configure proxy settings manually from code? It's really driving me crazy. It works when I run it from visual studio, both in master and debug mode, but it doesn't when I download it from the Microsoft Store. It's nonsense and impossible to debug, and each iteration takes hours.

    I'd really appreciate your help @timke and @Aurimas-Cernius . Thanks in advance.
     
  7. Tautvydas-Zilys

    Tautvydas-Zilys

    Unity Technologies

    Joined:
    Jul 25, 2013
    Posts:
    10,680
    Hey, we're looking at this. It seems specifically this breaks if you configure a proxy that has a "bypass" list. This bypass list is usually configured if your proxy doesn't support making web requests to particular web address. Most often this happens when trying to make web requests to your local area network IP address. This has generally been a rare case, so this wasn't the highest priority thing to address. Web requests that go through the proxy work just fine.

    Can you explain what you're trying to do and what exactly doesn't work?
     
  8. joseGuate97

    joseGuate97

    Joined:
    Mar 1, 2018
    Posts:
    57
    Hi @Tautvydas-Zilys ,

    Assuming it is something close to what you're saying, shouldn't it be a network error? I'm working with a log in form at the beginning of my app. Not only in the editor, but also when I hit play on visual studio (both in Debug or Master mode), if I disconnect the Wi-Fi, my app will show a dialog box that says "Cannot resolve destination host. ConnectionError," because I set a callback to do so after a network error happens. This is my code:

    Code (CSharp):
    1. private IEnumerator POST_Login(POST_LoginReqBody body, Action<UnityWebRequest, DownloadHandler> res, Action<string, UnityWebRequest> err)
    2.         {
    3.             using (var request = new UnityWebRequest(API_ACCOUNT_LOGIN, "POST"))
    4.             {
    5.                 // Prepare body of the request
    6.                 string bodyJSON = JsonUtility.ToJson(body);
    7.                 byte[] bodyRaw = System.Text.Encoding.UTF8.GetBytes(bodyJSON);
    8.  
    9.                 // Attach body and define request handler
    10.                 request.uploadHandler = (UploadHandler)new UploadHandlerRaw(bodyRaw);
    11.                 request.downloadHandler = (DownloadHandler)new DownloadHandlerBuffer();
    12.  
    13.                 // Set request header
    14.                 request.SetRequestHeader("Content-Type", "application/json");
    15.                 request.SetRequestHeader("Authorization", "<JSONWebToken_goes_here... not on this one in particular, maybe. But here...>");
    16.  
    17.                 // Send request
    18.                 yield return request.SendWebRequest();
    19.  
    20.                 // Handle basic errors...
    21.                 if (request.isNetworkError)
    22.                 {
    23.                     Debug.LogError("Network error. (POST_Login)");
    24.                     Debug.LogError(request.error);
    25.  
    26.                     err(request.error, request);
    27.                     yield break;
    28.                 }
    29.  
    30.                 if (request.isHttpError)
    31.                 {
    32.                     Debug.LogError("Http Error. (POST_Login)");
    33.                     Debug.LogError(request.error);
    34.                     err(request.error, request);
    35.                     yield break;
    36.                 }
    37.  
    38.                 // Handle a successful request
    39.                 Debug.Log("Requset Success");
    40.                 res(request, request.downloadHandler);
    41.  
    42.  
    43.             }
    44.         }
    Therefore, it seems that the UnityWebRequest API is not working at all. The request, I presume, never happens. That's why I don't get a request error.

    If what you tell me is true, shouldn't the app also not work when I hit play on Visual Studio in Debug/Master mode? It works just fine when I do it from there. In some way, I wish it didn't, because then I would be able to debug it closely. As I said, it's only when I download it from the Microsoft Store that I get something that doesn't work, which is very frustrating because every iteration takes several hours, if not a day or so.

    Please, help.
     
    Last edited: Aug 3, 2020
  9. joseGuate97

    joseGuate97

    Joined:
    Mar 1, 2018
    Posts:
    57
    Actually @Tautvydas-Zilys , seeing the UnityPlayer.log file I can see this:


    (Filename: C:\buildslave\unity\build\Runtime/Export/Debug/Debug.bindings.h Line: 35)

    Curl error 6: Could not resolve host: api.<myappwebhostgoeshere>.com


    However, although I can see the Debug.Log messages for a network error as shown in my code...

    Network error. (POST_Login)
    UnityEngine.Logger:Log(LogType, Object)
    UnityEngine.Debug:Log(Object)
    ReadingApp.DatabaseAPI.<POST_Login>d__21:MoveNext()
    ReadingApp.StaticCoroutineRunner.<MonitorRunning>d__1:MoveNext()
    UnityEngine.SetupCoroutine:InvokeMoveNext(IEnumerator, IntPtr)

    (Filename: C:\buildslave\unity\build\Runtime/Export/Debug/Debug.bindings.h Line: 35)

    Cannot resolve destination host
    UnityEngine.Logger:Log(LogType, Object)
    UnityEngine.Debug:Log(Object)
    System.Action`2:Invoke(T1, T2)
    ReadingApp.DatabaseAPI.<POST_Login>d__21:MoveNext()
    ReadingApp.StaticCoroutineRunner.<MonitorRunning>d__1:MoveNext()
    UnityEngine.SetupCoroutine:InvokeMoveNext(IEnumerator, IntPtr)

    ... the callback does not seem to be called at all. (Because I can't see the dialog box that I talked you about.) This is very strange behavior. In the editor, if I disconnect the WiFi, I will see such dialog box (called in the callback) saying there was a connection error, as intended. But the same doesn't happen in the UWP build (not even after I disconnect the WiFi). I am wondering there could be an issue with Coroutines in UWP that affects UnityWebRequest too, or similar.

    But if it is indeed a network error, well, I opened this thread of its own here https://forum.unity.com/threads/uni...resolve-destination-host-curl-error-6.944655/. Perhaps we should keep the conversation going in that thread.
     
  10. Tautvydas-Zilys

    Tautvydas-Zilys

    Unity Technologies

    Joined:
    Jul 25, 2013
    Posts:
    10,680
    It sounds you're running into a totally different issue from what is being discussed in this thread. To be absolutely clear, the issue here reproduces ONLY if you change windows internet settings to go through a proxy, and add a specific URL or IP address into the bypass list.