10

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);
    }
}
valentasm
  • 2,137
  • 23
  • 24
  • 1
    When you go into you Android project option and make sure the "HttpClient implementation" says `AndroidClientHandler` and what's the "SSL/TLS implementation" ? – Saamer Jan 23 '20 at 23:32
  • Xamarin.Android.Net.AndroidClientHandlerbtls – valentasm Jan 24 '20 at 10:40
  • When you changed the configuration to Release, do you still see the issue? Also does it work on iOS and can you share the code where you are setting the client handler to okhttp? – Saamer Jan 24 '20 at 16:06
  • I have same issue on Release. I coundnt test on iOs. I tested with exactly same code on console app and it works. I dont set any handler. Thats all code what i use. Also i dont use any library. – valentasm Jan 24 '20 at 19:25
  • Were you able to make the same code work in a console application? Or a tool like Postman – Saamer Feb 04 '20 at 19:10
  • Looks like you havent read question carefully. I stated that it works on console. Also mentioned again in comments. Also PostMan doesnt work with http/2. I just got idea to check with .net standart 2 lib or asp core 2, since i tested with asp core 3.1 which worked. – valentasm Feb 04 '20 at 22:02
  • Ah my bad. Can you provide a sample application? So I can replicate it on my computer – Saamer Feb 04 '20 at 22:04
  • I updated question with solution (github) and some instructions which i tried to fallow. Important to note that it works on 3.1 but dont on 2.2. What makes me nervous that grpc works so it must be way how to make it work without many nasty workarounds. – valentasm Feb 05 '20 at 14:37
  • @valentasm Did you manage to solve this? – Kavinda Gayashan Feb 18 '20 at 01:50
  • Sadly no. If you could target .net core 3 then there is no problem. Originally i wanted file transfer over htpp2, so i switched to http1 and my server for http1 one port and htpp2 another port. – valentasm Feb 18 '20 at 09:56
  • 1
    I have no issues calling grpc services in Xamarin.Forms. Like i said grpc works for me, but calling http2 dont work. – valentasm Feb 18 '20 at 20:13
  • 1
    @valentasm Since xamarin works for you, Can you please have a look at below question that I posted? https://stackoverflow.com/questions/60360430/why-does-xamarin-android-fails-to-send-grpc-http2-requests – Kavinda Gayashan Feb 23 '20 at 09:43
  • @valentasm Did you ever have a chance to try out grpc with Xamarin.Forms on iOS? – cost Apr 16 '20 at 04:09
  • No i havent. I will in second part of this year. I read that a lot about http2 and apple push notications or smth like that so assume it should work. What issue do you have? – valentasm Apr 16 '20 at 09:00
  • @valentasm Did you find a solution to your problem? I am currently running into the same problem – TheTanic Jan 17 '22 at 13:34
  • No. I just gave up. Even more i started to use grpc-web since it support blazor, iis. – valentasm Jan 17 '22 at 15:27

1 Answers1

0

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. enter image description here
  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); 
Saamer
  • 4,687
  • 1
  • 13
  • 55
  • 1
    1. .NET Core 3.0 and Xamarin. I think you misunderstand smth here 2. I said that i tried. Dont help. 3. I think i already tried both of them. Of course i have to try with fresh head now. – valentasm Jun 15 '20 at 20:50
  • 1,2 suggestion didnt helped. It could be server related too. I think i tried http2dotnet without success. Since grpc-web is release almost sure it gonna work on that. – valentasm Jul 06 '20 at 19:23
  • i dont think thats even working. it is an answer based on assumption not based on experience and testing – Emil May 18 '23 at 16:30
  • @Emil what error are you facing? Different firewalls & servers have different requirements, did you try all of them? – Saamer May 18 '23 at 17:41
  • when i observe with mitmproxy on mac and it is always 1.1 whatever you do. Did you the Ios app or your answer is for Android? – Emil May 19 '23 at 02:04
  • The logs in the question & the tag were for Android, and so was my answer @Emil – Saamer May 19 '23 at 12:55