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 Android和 Stackoverflow.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);
}
}
最佳答案
有几个可能的解决方案:
<AndroidHttpClientHandlerType>Xamarin.Android.Net.AndroidClientHandler</AndroidHttpClientHandlerType>
<AndroidTlsProvider>btls</AndroidTlsProvider>
然后我只需要在我的 HttpClient 中传递这个 HttpClientHandler:
httpClient = new HttpClient(new HttpClientHandler()
{
UseProxy = true
});
// 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/