static async Task Main(string[] args) { // DI var services = new ServiceCollection(); var loggerFactory = LoggerFactory.Create(logging => { logging.AddConsole(); logging.SetMinimumLevel(LogLevel.Debug); }); var serverErrors = new HttpStatusCode[] { HttpStatusCode.BadGateway, HttpStatusCode.GatewayTimeout, HttpStatusCode.ServiceUnavailable, HttpStatusCode.InternalServerError, HttpStatusCode.TooManyRequests, HttpStatusCode.RequestTimeout }; var gRpcErrors = new StatusCode[] { StatusCode.DeadlineExceeded, StatusCode.Internal, StatusCode.NotFound, StatusCode.ResourceExhausted, StatusCode.Unavailable, StatusCode.Unknown }; Func <HttpRequestMessage, IAsyncPolicy <HttpResponseMessage> > retryFunc = (request) => { return(Policy.HandleResult <HttpResponseMessage>(r => { var grpcStatus = StatusManager.GetStatusCode(r); var httpStatusCode = r.StatusCode; return (grpcStatus == null && serverErrors.Contains(httpStatusCode)) || // if the server send an error before gRPC pipeline (httpStatusCode == HttpStatusCode.OK && gRpcErrors.Contains(grpcStatus.Value)); // if gRPC pipeline handled the request (gRPC always answers OK) }) .WaitAndRetryAsync(3, (input) => TimeSpan.FromSeconds(3 + input), (result, timeSpan, retryCount, context) => { var grpcStatus = StatusManager.GetStatusCode(result.Result); Console.WriteLine($"Request failed with {grpcStatus}. Retry"); })); }; // https://grpcwebdemo.azurewebsites.net // gRPC services.AddGrpcClient <CountryServiceClient>(o => { o.Address = new Uri("https://localhost:5001"); }).AddPolicyHandler(retryFunc); var provider = services.BuildServiceProvider(); var client = provider.GetRequiredService <CountryServiceClient>(); // gRPC-Web //var handler = new GrpcWebHandler(GrpcWebMode.GrpcWebText, new HttpClientHandler()); //var channel = GrpcChannel.ForAddress("https://grpcwebdemo.azurewebsites.net", new GrpcChannelOptions //{ // HttpClient = new HttpClient(handler), // LoggerFactory = loggerFactory //}); //var clientWeb = new CountryServiceClient(channel); try { // Get all gRPC var countries = (await client.GetAllAsync(new EmptyRequest())).Countries.Select(x => new Country { CountryId = x.Id, Description = x.Description, CountryName = x.Name }).ToList(); Console.WriteLine("Found countries"); countries.ForEach(x => Console.WriteLine($"Found country {x.CountryName} ({x.CountryId}) {x.Description}")); // Get all gRPC - web //var countriesweb = (await clientWeb.GetAllAsync(new EmptyRequest())).Countries.Select(x => new Country //{ // CountryId = x.Id, // Description = x.Description, // CountryName = x.Name //}).ToList(); //Console.WriteLine("Found countries with gRPC-Web"); //countriesweb.ForEach(x => Console.WriteLine($"Found country with gRPC-Web: {x.CountryName} ({x.CountryId}) {x.Description}")); } catch (RpcException e) { var errors = e.GetValidationErrors(); // Gets validation errors list Console.WriteLine(e.Message); } }
// This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { #region Discount gRPC client // Enable support for unencrypted HTTP2 //AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true); //AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2Support", true); Random jitterer = new Random(); var loggerFactory = LoggerFactory.Create(logging => { logging.AddConsole(); logging.SetMinimumLevel(LogLevel.Debug); }); var serverErrors = new HttpStatusCode[] { HttpStatusCode.BadGateway, HttpStatusCode.GatewayTimeout, HttpStatusCode.ServiceUnavailable, HttpStatusCode.InternalServerError, HttpStatusCode.TooManyRequests, HttpStatusCode.RequestTimeout }; var gRpcErrors = new StatusCode[] { StatusCode.DeadlineExceeded, StatusCode.Internal, StatusCode.NotFound, StatusCode.ResourceExhausted, StatusCode.Unavailable, StatusCode.Unknown }; Func <HttpRequestMessage, IAsyncPolicy <HttpResponseMessage> > retryFunc = (request) => { return(Policy.HandleResult <HttpResponseMessage>(r => { var grpcStatus = StatusManager.GetStatusCode(r); var httpStatusCode = r.StatusCode; return (grpcStatus == null && serverErrors.Contains(httpStatusCode)) || // if the server send an error before gRPC pipeline (httpStatusCode == HttpStatusCode.OK && gRpcErrors.Contains(grpcStatus.Value)); // if gRPC pipeline handled the request (gRPC always answers OK) }) .WaitAndRetryAsync(3, (input) => TimeSpan.FromSeconds(3 + input), (result, timeSpan, retryCount, context) => { var grpcStatus = StatusManager.GetStatusCode(result.Result); Console.WriteLine($"Request failed with {grpcStatus}. Retry"); })); }; services.AddGrpcClient <DiscountProtoService.DiscountProtoServiceClient>(options => { options.Address = new Uri(Configuration["GrpcSettings:DiscountUrl"]); options.ChannelOptionsActions.Add(channelOptions => { channelOptions.Credentials = ChannelCredentials.Insecure; }); }).AddPolicyHandler(retryFunc); services.AddScoped <DiscountGrpcService>(); #endregion #region Redis connection configuration services.AddStackExchangeRedisCache(options => { options.Configuration = Configuration.GetValue <string>("CacheSettings:ConnectionString"); }); #endregion services.AddControllers(); services.AddSwaggerGen(c => { c.SwaggerDoc("v1", new OpenApiInfo { Title = "Basket.API", Version = "v1" }); }); #region Data repositories registration services.AddScoped <IBasketRepository, BasketRepository>(); #endregion }