乐趣区

关于后端:3-Caller-服务调用-dapr

前言

上一篇咱们讲了应用 HttpClient 的形式调用,那么如果咱们当初须要更换为通过 dapr 实现服务调用,咱们须要做哪些事件呢?

Caller.Dapr 入门

如果咱们的我的项目本来应用的是 Caller.HttpClient,当初心愿改为应用 Caller.Dapr,那么咱们须要做什么呢?

  1. 革新 Caller 服务调用 – HttpClient 的中的服务端,使得服务端反对 dapr 调用
  2. 调整客户端代码,使客户端反对通过 dapr 来做到服务调用,并达到与 HttpClient 调用雷同的后果

筹备工作

  • 装置.Net 6.0
  1. 创立 ASP.NET Core 空白解决方案Assignment03
  2. Assignment02 文件夹下的 Assignment.Server 复制到 Assignment03 的文件夹下,而后将我的项目 Assignment.Server 增加到解决方案 Assignment03
  3. 选中 Assignment.Server 并装置Masa.Utils.Development.Dapr.AspNetCore

    dotnet add package Masa.Utils.Development.Dapr.AspNetCore --version 0.4.0-rc1
  4. 批改 Assignment.Server 我的项目下的Program.cs

    // 疏忽命名空间援用
    
    var builder = WebApplication.CreateBuilder(args);
    
    // 增加 DaprStarter,用于服务端启动 dapr sidecar,革新服务端反对 dapr 调用的重点(倡议在开发环境下应用,线上环境应用 k8s 部署)builder.Services.AddDaprStarter(option =>
    {
        option.AppId = "Assignment-Server";
        option.DaprGrpcPort = 7007;
        option.DaprHttpPort = 7008;
        option.AppIdSuffix = string.Empty;
    });
    
    var app = builder.Build();
    /// 疏忽路由等

    Q: 什么是 DaprStarter?为什么要应用 DaprStarter?
    A: DaprStarter 是 Masa 团队开发进去用于治理 Dapr sidecar 的包,能够帮忙咱们在开发环境下很简略的应用 dapr sidecar

    Q: 为什么要指定 AppId、DaprGrpcPort、DaprHttpPort 等信息?
    A: 客户端调用须要失去 Dapr 的 AppId、设置 DaprGrpcPort、DaprHttpPort 是因为客户端演示我的项目没有应用 dapr sidecar,如果客户端我的项目也应用 dapr sidecar,此处能够不指定 DaprGrpcPort、DaprHttpPort,更多信息请参考文章

  5. 创立 ASP.NET Core 空我的项目 Assignment.Client.DaprClientWeb 作为客户端并装置Masa.Utils.Caller.DaprClient

    dotnet add package Masa.Utils.Caller.DaprClient --version 0.4.0-rc1
  6. 批改 Assignment.Client.DaprClientWeb 我的项目下的Program.cs

    using Masa.Utils.Caller.Core;
    using Masa.Utils.Caller.DaprClient;
    using Microsoft.AspNetCore.Mvc;
    
    var builder = WebApplication.CreateBuilder(args);
    builder.Services.AddCaller(option =>
    {
        // 留神: 与 Caller.HttpClient 相比,须要批改的中央
        options.UseDapr(masaDaprClientBuilder =>
        {masaDaprClientBuilder.Name = "userCaller"; // 以后 Caller 的别名(仅有一个 Caller 时能够不填),Name 不能反复
            masaDaprClientBuilder.IsDefault = true; // 默认的 Caller 反对注入 ICallerProvider 获取(仅有一个 Caller 时可不赋值)masaDaprClientBuilder.AppId = "Assignment-Server";// 设置以后 caller 下 Dapr 的 AppId
        });
    });
    var app = builder.Build();
    
    app.MapGet("/", () => "Hello HttpClientWeb.V1!");
    
    app.MapGet("/Test/User/Get", async ([FromServices] ICallerProvider callerProvider) =>
    {var user = await callerProvider.GetAsync<object, UserDto>("User", new { id = new Random().Next(1, 10) });
        return $"获取用户信息胜利:用户名称为:{user!.Name}";
    });
    
    app.MapGet("/Test/User/Add", async ([FromServices] ICallerProvider callerProvider) =>
    {var dateTimeOffset = new DateTimeOffset(DateTime.UtcNow);
        string timeSpan = dateTimeOffset.ToUnixTimeSeconds().ToString();
        var userName = "ss_" + timeSpan; // 模仿一个用户名
        string? response = await callerProvider.PostAsync<object, string>("User", new { Name = userName});
        return $"创立用户胜利了,用户名称为:{response}";
    });
    
    app.Run();
    
    public class UserDto
    {public int Id { get; set;}
    
        public string Name {get; set;} = default!;
    }
    

    相较于 Assignment.Client.HttpClientWebAssignment.Client.DaprClientWeb 仅仅是更改了 Program.cs,将UseHttpClient 改为UseDapr,其余代码无需批改

  7. 增加环境变量DAPR_GRPC_PORT,值为7007DAPR_HTTP_PORT,值为7008

    Q: 为什么要增加环境变量?
    A: 因为以后客户端并未应用 dapr sidecar,若以后客户端也应用 dapr sidecar,此处能够不增加环境变量

当初 Caller 的 HttpClient 版本就能够应用了,别离启动 Assignment.ServerAssignment.Client.DaprClientWeb 服务,浏览器拜访http://localhost:5042/Test/User/Gethttp://localhost:5042/Test/User/Add,别离输入对应的获取用户信息胜利以及创立用户胜利的提醒,则证实调用胜利了

DaprClient 最佳实际

Assignment.Client.DaprClientWeb的写法比较简单,其用法与 Assignment.Client.HttpClientWeb 基本一致,与 Caller.HttpClient 相似,DaprClient 咱们举荐应用上面的写法:

  1. 创立 ASP.NET Core 空我的项目 Assignment.Client.DaprClientWeb.V2 作为调用方 V2 版本
  2. 选中 Assignment.Client.DaprClientWeb.V2 并装置Masa.Utils.Caller.DaprClient

    dotnet add package Masa.Utils.Caller.DaprClient --version 0.4.0-rc1
  3. 增加类ServerCallerBase (对应服务端服务)

    using Masa.Utils.Caller.DaprClient;
    
    namespace Assignment.Client.DaprClientWeb.V2;
    
    /// <summary>
    /// 留神:ServerCallerBase 是抽象类哟(抽象类不会被 DI 注册), 与应用 Caller.HttpClient 相比,须要批改的是继承的基类改为 DaprCallerBase
    /// </summary>
    public abstract class ServerCallerBase : DaprCallerBase
    {protected override string AppId { get; set;} = "Assignment-Server";// 设置以后 Caller 须要申请的服务端我的项目 Dapr 的 AppId
    
        public ServerCallerBase(IServiceProvider serviceProvider) : base(serviceProvider)
        {}}
  4. 增加类UserCaller.cs

    namespace Assignment.Client.DaprClientWeb.V2;
    
    public class UserCaller : ServerCallerBase
    {public UserCaller(IServiceProvider serviceProvider) : base(serviceProvider)
        { }
    
        /// <summary>
        /// 调用服务获取用户信息
        /// </summary>
        /// <param name="id"> 用户 id</param>
        /// <returns></returns>
        public Task<UserDto?> GetUserAsync(int id)
            => CallerProvider.GetAsync<object, UserDto>("User", new { id = id});
    
        /// <summary>
        /// 调用服务增加用户
        /// </summary>
        /// <param name="userName"></param>
        /// <returns></returns>
        public Task<string?> AddUserAsync(string userName)
            => CallerProvider.PostAsync<object, string>("User", new { Name = userName});
    }
    
    public class UserDto
    {public int Id { get; set;}
    
        public string Name {get; set;} = default!;
    }
  5. 增加环境变量DAPR_GRPC_PORT,值为7007DAPR_HTTP_PORT,值为7008

最初,别离启动 Assignment.ServerAssignment.Client.DaprClientWeb.V2 服务,浏览器拜访http://localhost:5102/Test/User/Gethttp://localhost:5102/Test/User/Add,别离输入对应的获取用户信息胜利以及创立用户胜利的提醒,则证实调用胜利了

常见问题

在开发中咱们会遇到各种各样的问题,上面就来列举几个咱们我的项目中遇到的问题:

  • 一个我的项目在同一个 k8s 集群部署了两套环境,为什么会呈现代码调用凌乱(开发环境调用线上环境)?

    在于同一个 K8s 集群下,dapr 会将服务组网,并将它们认为是同一个服务(AppId 统一的服务)。
  • 如何解决同一个 k8s 集群中调用凌乱的问题?

    解决方案有两种:1. 将不同环境下的服务别离部署在不同的 K8s 集群
    2. 依据环境调整绝对应服务的 dapr sidecar 的配置,其 `AppId` 的命名规定:`AppId`-` 环境名 `。批改自定义 Caller 的规定:public abstract class CustomizeDaprCallerBase : DaprCallerBase
    {protected CustomizeDaprCallerBase(IServiceProvider serviceProvider) : base(serviceProvider)
        {var hostEnvironment = serviceProvider.GetRequiredService<IWebHostEnvironment>();
            if (!hostEnvironment.IsDevelopment() || hostEnvironment.IsStaging())
                AppId = AppId + "-" + hostEnvironment.EnvironmentName;
        }
    }
  • 如何批改反对自定义 Header?

    目前 Caller.Dapr 不反对自定义 Header,目前只能应用 `SendAsync` 能力自定义 Header,不过此性能曾经在 0.5.0 的开发计划中,在 0.5.0 中会反对

总结

应用 Masa 提供的 Caller 服务,有助于咱们的我的项目在后期没有应用 Dapr 的状况下先利用 Caller.HttpClient 做缓冲,等前期时机成熟,只须要更改绝对应的 CallerBase 即可,其余代码根本不须要调整,加重了咱们的开发成本,并且不同的 Caller 依然能够很灵便的调整超时工夫、Header 等信息,并且 Caller 默认提供了解决异样的性能,当调用出错后,会主动抛出异样,让咱们能够更分心的解决业务。

但目前 Caller 还有不足之处,目前 Caller.Dapr 版针对申请头解决的并不欠缺,除此之外,目前不反对 Content-Type 为非 Json 类型,这块性能会在 0.5.0 版本中加以反对欠缺

本章源码

Assignment03

https://github.com/zhenlei520…

开源地址

MASA.BuildingBlocks:https://github.com/masastack/…

MASA.Contrib:https://github.com/masastack/…

MASA.Utils:https://github.com/masastack/…

MASA.EShop:https://github.com/masalabs/M…

MASA.Blazor:https://github.com/BlazorComp…

如果你对咱们的 MASA Framework 感兴趣,无论是代码奉献、应用、提 Issue,欢送分割咱们

退出移动版