dotnet / MobileBlazorBindings

Experimental Mobile Blazor Bindings - Build native and hybrid mobile apps with Blazor
MIT License
1.2k stars 151 forks source link

[Request] Add samples with calls to gRPC and a Web API #98

Open ogauthier opened 4 years ago

ogauthier commented 4 years ago

I'm trying to make a sample application that communicates with gRPC Server with the new GprcWeb package and can't make it to work on my Android simulator. I also failed to make a call with HttpClient. Can you add new samples that could show how?

Eilon commented 4 years ago

This is a great suggestion, I will look into it.

In the meantime anything you find regarding gRPC in Xamarin.Forms should work the same in Mobile Blazor Bindings, aside from the UI part. I found some threads here that talk about it in general:

Slevya commented 3 years ago

@ogauthier @Eilon GRPC working as well on MBB (we are using Hybrid templates)

You can directly use Grpc (HttpProtocols.Http2) for fast communications, instead of GrpcWeb, which using http1 protocol

Benefits here: (https://factoryhr.medium.com/http-2-the-difference-between-http-1-1-benefits-and-how-to-use-it-38094fa0e95b)

Benefits of Grpc, instead of GrpcWeb:

GrpcWeb (gRPC methods):

(Source: https://docs.microsoft.com/en-us/aspnet/core/grpc/browser?view=aspnetcore-5.0#grpc-web-and-streaming)

Grpc (gRPC methods):

(Source: https://docs.microsoft.com/en-us/aspnet/core/grpc/services?view=aspnetcore-5.0#implement-grpc-methods)


On Xamarin client

  1. Share project: add packages -> Google.Protobuf (3.15.3), Gprc.Core(2.32.0), Gprc.Tools(2.32.0)

Why Grpc.Core is 2.32.0? cause upper versions have many problems with linking in iOS

How to solve it? Here: (source: https://techblog.livongo.com/fixing-grpc-xamarin-ios-linking-errors) and here: https://github.com/grpc/grpc/issues/19172#issuecomment-730364709

add @using Grpc.Core in your _Imports.razor
add Protos (enough on share project)
  1. Anrdoid project: add package -> Grpc.Core (2.32.0) Works perfectly

  2. iOS project: add package -> Grpc.Core (2.32.0)

add to your ios csproj ->

<Target Name="GrpcCoreShim" BeforeTargets="CoreCompile">
    <PropertyGroup>
      <GrpcCoreTargetsRelativePath>..\..\..\.nuget\packages\grpc.core\2.32.0</GrpcCoreTargetsRelativePath>
    </PropertyGroup>
    <ConvertToAbsolutePath Paths="$(GrpcCoreTargetsRelativePath)">
      <Output TaskParameter="AbsolutePaths" PropertyName="GrpcCoreTargetsAbsPath" />
    </ConvertToAbsolutePath>
    <ItemGroup>
      <NativeReference Remove="libgrpc_csharp_ext.a" />
      <NativeReference Remove="libgrpc.a" />
      <NativeReference Include="$(GrpcCoreTargetsAbsPath)\native\ios\universal\libgrpc_csharp_ext.a">
        <Kind>Static</Kind>
        <ForceLoad>True</ForceLoad>
        <IsCxx>True</IsCxx>
      </NativeReference>
      <NativeReference Include="$(GrpcCoreTargetsAbsPath)\native\ios\universal\libgrpc.a">
        <Kind>Static</Kind>
        <ForceLoad>True</ForceLoad>
        <IsCxx>True</IsCxx>
      </NativeReference>
    </ItemGroup>
  </Target>

Attention: The amount of ..\ in < GrpcCoreTargetsRelativePath> is individual...

Tested on Simulator (Iphone 11 14.4), and real device Iphone Xr (14.4) Works perfectly

  1. If you are using hybrid template, then you can add Grpc Channel like singleton in dependency services in App.cs

    services.AddSingleton(services =>
                    {
                        AppContext.SetSwitch(
               "System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true); //use if unencrypted connection 
                        return new Channel("server_ip:5001", ChannelCredentials.Insecure); // if localhost = "127.0.0.1:5001" //ChannelCredentials.Insecure - if unencrypted connection
                    });
  2. Inject Grpc channel on blazor views like ->

    @code {
    [Inject]
    Channel grpcChannel { get; set; }
    
    protected override async Task OnInitializedAsync()
    {
        var client = new YourProtoService.YourProtoClient(grpcChannel);
        try
        {
            var reply = await client.YourProtoRpc(new YourProtoRequest);
            //TODO some work with reply
        }
        catch (RpcException rpc)
        {
            //TODO catch when rpc exceptions, e.g Unauthenticated or smthng
        }
        catch (Exception e)
        {
            //TODO catch when others exceptions
        }
    }
    }

    On Server

You can use GrpcService template (one of asp net core templates) In Program.cs

public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                    webBuilder.UseKestrel(options =>
                    {
                        options.Listen(IPAddress.Loopback, port: 4099); //for localhost
                        options.Listen(IPAddress.Any, port: 5001, listenOptions =>
                        {
                            listenOptions.Protocols = HttpProtocols.Http2;
                        });                      
                    });
                });

In middleware (Startup.cs, method Configure)

  app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
               //add other endpoints like asp net core mvc, api
                endpoints.MapGrpcService<YourService>(); //.EnableGrpcWeb() - for grpc web
            });
Eilon commented 3 years ago

Thank you @Slevya for sharing!