How to make calls to HTTP2 on Xamarin.Forms

只谈情不闲聊 提交于 2021-02-06 21:34:55

问题


gRpc for Xamarin.Forms with .Net Standart 2.0 works on http2, so it should be some way to make HttpClient calls or reuse existing gRpc functionality. It could be that i missing something.

Sample app to reproduce issue. You need to host gRpc service somewhere. WebClient call is in AboutPage.xaml.cs aslo test project with asp core 3.1 in web folder. XamarinHttp2WithBackend GitHub

Fallowing instructions Microsoft.com - HttpClient Stack and SSL/TLS Implementation Selector for Android and Stackoverflow.com - Use HTTP 2 with HttpClient in .Net didnt helped either.

For Asp Core 3.1 console app you could do (bellow) and works. It wont works on 2.2 and lower

AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);

var client = new HttpClient();
var req = new HttpRequestMessage(HttpMethod.Get, $"http://123.123.123.123:1234/ping/")
{
    Version = new Version(2, 0),
};

var response = await client.SendAsync(req);

Using same on Xamarin throws exception

 Java.IO.IOException: unexpected end of stream on com.android.okhttp.Address@ce6f1800 ---> Java.IO.EOFException: 
 not found: size=17 content=0000080700000000000000000000000001...
01-23 15:10:13.472 I/MonoDroid(28829):    --- End of inner exception stack trace ---
01-23 15:10:13.472 I/MonoDroid(28829):   at Java.Interop.JniEnvironment+InstanceMethods.CallIntMethod (Java.Interop.JniObjectReference instance, Java.Interop.JniMethodInfo method, Java.Interop.JniArgumentValue* args) [0x0006e] in <e7e2d009b69d4e5f9a00e6ee600b8a8e>:0 
01-23 15:10:13.472 I/MonoDroid(28829):   at Java.Interop.JniPeerMembers+JniInstanceMethods.InvokeVirtualInt32Method (System.String encodedMember, Java.Interop.IJavaPeerable self, Java.Interop.JniArgumentValue* parameters) [0x0002a] in <e7e2d009b69d4e5f9a00e6ee600b8a8e>:0 
01-23 15:10:13.472 I/MonoDroid(28829):   at Java.Net.HttpURLConnection.get_ResponseCode () [0x0000a] in <d706cf8faf5542949900cf6d57864528>:0 
01-23 15:10:13.472 I/MonoDroid(28829):   at Xamarin.Android.Net.AndroidClientHandler+<>c__DisplayClass46_0.<DoProcessRequest>b__2 () [0x00000] in <d706cf8faf5542949900cf6d57864528>:0 
01-23 15:10:13.472 I/MonoDroid(28829):   at System.Threading.Tasks.Task`1[TResult].InnerInvoke () [0x0000f] in /Users/builder/jenkins/workspace/archive-mono/2019-08/android/release/external/corert/src/System.Private.CoreLib/src/System/Threading/Tasks/Future.cs:534 
01-23 15:10:13.472 I/MonoDroid(28829):   at System.Threading.Tasks.Task.Execute () [0x00000] in /Users/builder/jenkins/workspace/archive-mono/2019-08/android/release/external/corert/src/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs:2319 

Solution setting for DEBUG

<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>portable</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug</OutputPath>
<DefineConstants>DEBUG;</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AndroidLinkMode>None</AndroidLinkMode>
<AotAssemblies>false</AotAssemblies>
<EnableLLVM>false</EnableLLVM>
<AndroidEnableProfiledAot>false</AndroidEnableProfiledAot>
<BundleAssemblies>false</BundleAssemblies>
<AndroidSupportedAbis>
</AndroidSupportedAbis>
<EmbedAssembliesIntoApk>false</EmbedAssembliesIntoApk>
<Debugger>Xamarin</Debugger>
<AndroidUseSharedRuntime>true</AndroidUseSharedRuntime>
<AndroidUseAapt2>false</AndroidUseAapt2>
<AndroidHttpClientHandlerType>Xamarin.Android.Net.AndroidClientHandler</AndroidHttpClientHandlerType>
<AndroidTlsProvider>btls</AndroidTlsProvider>
</PropertyGroup>

My asp startup. I use it with grp service along. Publish as console single executable

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddGrpc((options => { options.EnableDetailedErrors = true; }));
        services.AddMvc(options => options.EnableEndpointRouting = false);

        //services.AddDbContext<PuvDbContext>();
        services.AddScoped<IAccountService, AccountService>();
        services.AddSingleton<IFirebirdService, FirebirdService>();
        services.AddSingleton<IClassificatorService, ClassificatorService>();
        services.AddSingleton<IClassificatorRepository, ClassificatorRepository>();

        services.AddControllers();
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        app.UseRouting();
        app.UseMvcWithDefaultRoute();

        app.UseStaticFiles();
        app.UseMvc();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapGrpcService<GreeterService>();
            endpoints.MapGrpcService<AccountController>();
            endpoints.MapGrpcService<ReviewController>();
            endpoints.MapGrpcService<StaticDataController>();
            endpoints.MapGrpcService<TaskController>();
            endpoints.MapControllers();
        });


    }
}

My controller method which i call

[Route("files")]
public class FileController : Controller
{
    public FileController()
    {       
    }

    [HttpGet("hi")]
    public async Task<HttpResponseMessage> GetTest()
    {
        return new HttpResponseMessage(HttpStatusCode.OK);
    }
}

回答1:


There's a few possible solutions:

  1. If you simply update your Target framework to .NET Standard 2.1 or newer, then that should fix your problem. If you can't do that because your solution in older, then try the rest.
  2. Open your Android project options and then in "Android build", update the HttpClient implementation value to "AndroidClientHandler" or any other value and try again, and this got added in the CSPROJ for that config
<AndroidHttpClientHandlerType>Xamarin.Android.Net.AndroidClientHandler</AndroidHttpClientHandlerType>
<AndroidTlsProvider>btls</AndroidTlsProvider>

And then I just had to pass this HttpClientHandler in my HttpClient:

httpClient = new HttpClient(new HttpClientHandler()
{
    UseProxy = true
});
  1. If that doesn't work either, then you have to use one of these two nuget packages http2dotnet (https://github.com/Matthias247/http2dotnet) or httptwo (https://github.com/Redth/HttpTwo) instead as shown in their GitHub:
// Uri to request
var uri = new Uri ("http://somesite.com:80/index.html");

// Create a Http2Client
var http2 = new Http2Client (uri);

// Specify any custom headers
var headers = new NameValueCollection ();
headers.Add ("some-header", "value");

// For some requests you may have a request body
byte[] data = null; 

// Await our response
var response = await http2.Send (uri, HttpMethod.Get, headers, data); 


来源:https://stackoverflow.com/questions/59887091/how-to-make-calls-to-http2-on-xamarin-forms

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!