はじめに
ASP.NET Core で gRPC と gRPC-Web を 1 つのアプリでホストできることは確認した。
tnakamura.hatenablog.com
gRPC と MVC はどうだろうか?試してみた。
gRPC サーバーに Web API を追加
GreeterController
using Microsoft.AspNetCore.Mvc;
namespace HelloGrpcWeb.Controllers
{
[ApiController]
[Route("api/greeter")]
public class GreeterController : ControllerBase
{
[HttpGet("hello/{name}")]
public IActionResult Hello(string name)
{
return Ok(new
{
Message = $"Hello {name}",
});
}
}
}
Startup
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
namespace HelloGrpcWeb
{
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddGrpc();
services.AddControllers();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseGrpcWeb();
app.UseEndpoints(endpoints =>
{
endpoints.MapGrpcService<GreeterService>()
.EnableGrpcWeb();
endpoints.MapControllers();
endpoints.MapGet("/", async context =>
{
await context.Response.WriteAsync("Communication with gRPC endpoints must be made through a gRPC client. To learn how to create a client, visit: https://go.microsoft.com/fwlink/?linkid=2086909");
});
});
}
}
}
クライアントに Web API を呼び出すサンプルを追加
gRPC と同じアドレスで Web API もホストする場合、HTTP/2 を使う必要がある。でないと、サーバー側で「HTTP/2 over TLS was not negotiated on an HTTP/2-only endpoint.」っていうエラーになり、リクエスト送信に失敗する。
using System;
using System.Net.Http;
using System.Threading.Tasks;
using Grpc.Net.Client;
using Grpc.Net.Client.Web;
namespace HelloGrpcWeb.Client
{
class Program
{
const string Address = "https://localhost:5001";
static async Task Main(string[] args)
{
await Grpc();
await GrpcWeb();
await Mvc();
Console.ReadLine();
}
static async Task Grpc()
{
var channel = GrpcChannel.ForAddress(Address);
var client = new Greeter.GreeterClient(channel);
var reply = await client.SayHelloAsync(new HelloRequest
{
FirstName = "Takefusa",
LastName = "Kubo",
});
Console.WriteLine($"gRPC:{reply.Message}");
}
static async Task GrpcWeb()
{
var channel = GrpcChannel.ForAddress(Address, new GrpcChannelOptions
{
HttpHandler = new GrpcWebHandler(
new HttpClientHandler()),
});
var client = new Greeter.GreeterClient(channel);
var reply = await client.SayHelloAsync(new HelloRequest
{
FirstName = "Takehiro",
LastName = "Tomiyasu",
});
Console.WriteLine($"gRPC Web:{reply.Message}");
}
static async Task Mvc()
{
var client = new HttpClient
{
BaseAddress = new Uri(Address),
DefaultRequestVersion = new Version(2, 0),
};
var response = await client.GetAsync(
"/api/greeter/hello/Douan");
var body = await response.Content.ReadAsStringAsync();
Console.WriteLine($"MVC:{body}");
}
}
}
実行結果
HTTP/2 ではあるが、Web API も呼び出せた。
おわりに
gRPC と gRPC-Web、それに MVC を 1 つのアプリケーションでホストすることはできた。ただ、詰め込んだのはいいものの、MVC で実装した Web API を呼び出すには HTTP/2 が必要、というのが問題になるかもしれないな。