c# - 如何在 Xamarin.Forms 上调用 HTTP2

标签 c# android xamarin http2

gRpc for Xamarin.Forms with .Net Standart 2.0 适用于 http2,因此它应该是进行 HttpClient 调用或重用现有 gRpc 功能的某种方式。可能是我错过了一些东西。

重现问题的示例应用程序。您需要在某处托管 gRpc 服务。 WebClient 调用位于 AboutPage.xaml.cs aslo 测试项目中,其中包含 web 文件夹中的 asp core 3.1。
XamarinHttp2WithBackend GitHub

休耕说明 Microsoft.com - HttpClient Stack and SSL/TLS Implementation Selector for AndroidStackoverflow.com - Use HTTP 2 with HttpClient in .Net也没有帮助。

对于 Asp Core 3.1 控制台应用程序,您可以执行(如下)并且可以工作。它不适用于 2.2 及更低版本

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);

在 Xamarin 上使用相同会引发异常
 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 


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>

我的asp启动。我将它与grp服务一起使用。
发布为控制台单个可执行文件
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();
        });


    }
}

我调用的 Controller 方法
[Route("files")]
public class FileController : Controller
{
    public FileController()
    {       
    }

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

最佳答案

有几个可能的解决方案:

  • 如果您只是将 Target 框架更新到 .NET Standard 2.1 或更高版本,那么应该可以解决您的问题。如果您不能这样做,因为您的解决方案较旧,请尝试其余的。
    enter image description here
  • 打开您的 Android 项目选项,然后在“Android build”中,将 HttpClient 实现值更新为“AndroidClientHandler”或任何其他值并重试,这已添加到该配置的 CSPROJ 中
  • <AndroidHttpClientHandlerType>Xamarin.Android.Net.AndroidClientHandler</AndroidHttpClientHandlerType>
    <AndroidTlsProvider>btls</AndroidTlsProvider>
    

    然后我只需要在我的 HttpClient 中传递这个 HttpClientHandler:
    httpClient = new HttpClient(new HttpClientHandler()
    {
        UseProxy = true
    });
    
  • 如果这也不起作用,那么您必须使用这两个 nuget 包之一 http2dotnet ( https://github.com/Matthias247/http2dotnet ) 或 httptwo ( https://github.com/Redth/HttpTwo ),如他们的 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); 
    

    关于c# - 如何在 Xamarin.Forms 上调用 HTTP2,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59887091/

    相关文章:

    c# - 在 MonoMac 中绘图

    c# - Selenium IE 自动化

    java - 在 Android 中录制声音时出错

    c# - 在 Xamarin.Forms 中存储应用程序数据的最佳 Environment.SpecialFolder 是什么?

    android - Xamarin webview 在 Release模式下不工作——Visual Studio 2013 和 2015

    c# - ReSharper 警告 : "Static field in generic type"

    Android + Groovy + Android 注解

    android - 我的相机 View 与 GLSurfaceView 重叠...但我希望它被 GLSurfaceView 覆盖

    c# - 从 Xamarin Android 的 c 源代码创建共享库

    c# - Razor 中枚举下拉列表的显示名称