c# - 如何在 Xamarin.Forms 上调用 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
Fallowing instructions Microsoft.com - HttpClient Stack and SSL/TLS Implementation Selector for Android和Stackoverflow.com - 在 .Net 中使用 HTTP 2 和 HttpClient也没有帮助。
对于 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();
});
}
}
我调用的控制器方法
[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 或更高版本,那么应该可以解决您的问题。如果您不能这样做,因为您的解决方案较旧,请尝试其余的。
- 打开您的 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);
推荐阅读
- ios - 每个元素值过滤数组的语法是什么?
- r - 用密码子对 DNA 序列进行分组
- algorithm - 相对于其他两个点的位置移动一个点的算法,
- python - 本地 python 包安装不再复制包?
- sql - Presto SQL:“日期”的占位符,必须大于任何其他日期
- c# - AddForceExplosion 仅影响 y 轴统一
- monetdb - MonetDB 设置特定的嵌入式 python 版本
- mysql - 如何从文本文件中删除特殊字符
- database - python - 如何使用PyMongo有条件地从一个集合中复制字段并将它们添加到MongoDB中的另一个?
- laravel - 如何查询存储在数据库中的会话