Xamarin: HTTP GETリクエスト

概要

XamarinでSystem.Net.Http.HttpClientを使用してHTTPのGETリクエストを行う。

docs.microsoft.com

サンプルコード

static readonly HttpClient client = new HttpClient();  // A)

async void OnButtonClicked(System.Object sender, System.EventArgs eventArgs)
{
    Console.WriteLine("Button clicked");  // B)
    try
    {
        await HttpRequestAsync();
    }
    catch (Exception e)
    {
        Console.WriteLine($"{e}");  // C)
    }
}

private static async Task HttpRequestAsync()
{
    HttpResponseMessage response = await client.GetAsync("https://example.com/");
    response.EnsureSuccessStatusCode();
    string responseBody = await response.Content.ReadAsStringAsync();
    Console.WriteLine("responseBody=" + responseBody);
}

A) HttpClientクラスのインスタンスは一度生成したインスタンスを繰り返し使用する前提で設計されているのでクラス内で一つだけ生成する。*実際にはアプリケーション内で一つだけになるよう実装する。

B) GetAsyncメソッドは非同期なので、ボタンをクリックした際に呼び出されるコールバックメソッドをasyncにしてその中で実行する。

C) 例外が発生するとアプリがクラッシュするので、例外の内容を出力する。

実行結果

responseBody=<!doctype html>
<html>
<head>
    <title>Example Domain</title>

    <meta charset="utf-8" />
    <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <style type="text/css">
    body {
        background-color: #f0f0f2;
        margin: 0;
        padding: 0;
        font-family: -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
        
    }
    div {
        width: 600px;
        margin: 5em auto;
        padding: 2em;
        background-color: #fdfdff;
        border-radius: 0.5em;
        box-shadow: 2px 3px 7px 2px rgba(0,0,0,0.02);
    }
    a:link, a:visited {
        color: #38488f;
        text-decoration: none;
    }
    @media (max-width: 700px) {
        div {
            margin: 0 auto;
            width: auto;
        }
    }
    </style>    
</head>

<body>
<div>
    <h1>Example Domain</h1>
    <p>This domain is for use in illustrative examples in documents. You may use this
    domain in literature without prior coordination or asking for permission.</p>
    <p><a href="https://www.iana.org/domains/example">More information...</a></p>
</div>
</body>
</html>

エラーが発生した場合の実行結果

例えばURLを"https://exmple.co"とした場合、以下の例外が発生する。

Androidでの実行結果

Java.Net.UnknownHostException: Unable to resolve host "exmple.co": No address associated with hostname ---> Java.Lang.RuntimeException: android_getaddrinfo failed: EAI_NODATA (No address associated with hostname)
   --- End of inner exception stack trace ---
    at com.android.okhttp.internal.http.RouteSelector.next04-29 13:54:30.935 I/mono-stdout( 8701):   at Java.Interop.JniEnvironment+InstanceMethods.CallVoidMethod (Java.Interop.JniObjectReference instance, Java.Interop.JniMethodInfo method, Java.Interop.JniArgumentValue* args) [0x0006e] in <26521a5118b44c858c385715922b9d5d>:0 
  at Java.Interop.JniPeerMembers+JniInstanceMethods.InvokeAbstractVoidMethod (System.String encodedMember, Java.Interop.IJavaPeerable self, Java.Interop.JniArgumentValue* parameters) [0x00014] in <26521a5118b44c858c385715922b9d5d>:0 
  at Javax.Net.Ssl.HttpsURLConnectionInvoker.Connect () [0x0000a] in <4ccdb3137d974856b786e1aeebbfbab6>:0 
  at Xamarin.Android.Net.AndroidClientHandler+<>c__DisplayClass44_0.<ConnectAsync>b__0 () [0x0005a] in <4ccdb3137d974856b786e1aeebbfbab6>:0 
  at System.Threading.Tasks.Task.InnerInvoke () [0x0000f] in <5e602907309a47679d31716bdfe8432e>:0 
  at System.Threading.Tasks.Task.Execute () [0x00000] in <5e602907309a47679d31716bdfe8432e>:0 
--- End of stack trace from previous location where exception was thrown ---
    at com.android.okhttp.internal.huc.HttpUR04-29 13:54:30.935 I/mono-stdout( 8701): 
  at Xamarin.Android.Net.AndroidClientHandler.SendAsync (System.Net.Http.HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) [0x002cf] in <4ccdb3137d974856b786e1aeebbfbab6>:0 
  at System.Net.Http.HttpClient.FinishSendAsyncBuffered (System.Threading.Tasks.Task`1[TResult] sendTask, System.Net.Http.HttpRequestMessage request, System.Threading.CancellationTokenSource cts, System.Boolean disposeCts) [0x0017e] in <e03aa70ca0174600ac09fcf1848e1777>:0 
  at XamarinHttp.MainPage.HttpRequestAsync () [0x0007b] in <a481c4eb9a264343915901e50ab7469d>:0 
  at XamarinHttp.MainPage.OnButtonClicked (System.Object sender, System.EventArgs eventArgs) [0x00077] in <a481c4eb9a264343915901e50ab7469d>:0 
  --- End of managed Java.Net.UnknownHostException stack trace ---
java.net.UnknownHostException: Unable to resolve host "exmple.co": No address associated with hostname
    at java.net.Inet6AddressImpl.lookupHostByName(Inet6AddressImpl.java:157)
    at java.net.Inet6AddressImpl.lookupAllHostAddr(Inet6AddressImpl.java:105)
    at java.net.InetAddress.getAllByName(InetAddress.java:1154)
    at com.android.okhttp.Dns$1.lookup(Dns.java:39)
    at com.android.okhttp.internal.http.RouteSelector.resetNextInetSocketAddress(RouteSelector.java:175)
    at com.android.okhttp.internal.http.RouteSelector.nextProxy(RouteSelector.java:141)
    at com.android.okhttp.internal.http.RouteSelector.next(RouteSelector.java:83)
    at com.android.okhttp.internal.http.StreamAllocation.findConnection(StreamAllocation.java:174)
    at com.android.okhttp.internal.http.StreamAllocation.findHealthyConnection(StreamAllocation.java:126)
    at com.android.okhttp.internal.http.StreamAllocation.newStream(StreamAllocation.java:95)
    at com.android.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:281)
    at com.android.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:224)
    at com.android.okhttp.internal.huc.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:461)
    at com.android.okhttp.internal.huc.HttpURLConnectionImpl.connect(HttpURLConnectionImpl.java:127)
    at com.android.okhttp.internal.huc.DelegatingHttpsURLConnection.connect(DelegatingHttpsURLConnection.java:89)
    at com.android.okhttp.internal.huc.HttpsURLConnectionImpl.connect(HttpsURLConnectionImpl.java:26)
Caused by: android.system.GaiException: android_getaddrinfo failed: EAI_NODATA (No address associated with hostname)
    at libcore.io.Linux.android_getaddrinfo(Native Method)
    at libcore.io.BlockGuardOs.android_getaddrinfo(BlockGuardOs.java:172)
    at java.net.Inet6AddressImpl.lookupHostByName(Inet6AddressImpl.java:137)
    ... 15 more

iOSでの実行結果

2020-04-29 14:07:33.908 XamarinHttp.iOS[2298:767706] System.Net.Http.HttpRequestException: A server with the specified hostname could not be found. ---> Foundation.NSErrorException: Error Domain=NSURLErrorDomain Code=-1003 "A server with the specified hostname could not be found." UserInfo={_kCFStreamErrorCodeKey=8, NSUnderlyingError=0x2801b7a80 {Error Domain=kCFErrorDomainCFNetwork Code=-1003 "(null)" UserInfo={_kCFStreamErrorCodeKey=8, _kCFStreamErrorDomainKey=12}}, _NSURLErrorFailingURLSessionTaskErrorKey=LocalDataTask <C61274F2-3338-4C46-8973-22E59D4FDE67>.<1>, _NSURLErrorRelatedURLSessionTaskErrorKey=(
    "LocalDataTask <C61274F2-3338-4C46-8973-22E59D4FDE67>.<1>"
), NSLocalizedDescription=A server with the specified hostname could not be found., NSErrorFailingURLStringKey=https://exmple.co/, NSErrorFailingURLKey=https://exmple.co/, _kCFStreamErrorDomainKey=12}
   --- End of inner exception stack trace ---
  at System.Net.Http.NSUrlSessionHandler.SendAsync (System.Net.Http.HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) [0x001d4] in /Library/Frameworks/Xamarin.iOS.framework/Versions/13.16.0.13/src/Xamarin.iOS/Foundation/NSUrlSessionHandler.cs:462 
  at System.Net.Http.HttpClient.FinishSendAsyncBuffered (System.Threading.Tasks.Task`1[TResult] sendTask, System.Net.Http.HttpRequestMessage request, System.Threading.CancellationTokenSource cts, System.Boolean disposeCts) [0x0017e] in /Library/Frameworks/Xamarin.iOS.framework/Versions/Current/src/Xamarin.iOS/external/corefx/src/System.Net.Http/src/System/Net/Http/HttpClient.cs:506 
  at XamarinHttp.MainPage.HttpRequestAsync () [0x0002f] in /Users/shindo/Projects/XamarinHttp/XamarinHttp/MainPage.xaml.cs:31 
  at XamarinHttp.MainPage.OnButtonClicked (System.Object sender, System.EventArgs eventArgs) [0x0002e] in /Users/shindo/Projects/XamarinHttp/XamarinHttp/MainPage.xaml.cs:54