关于后端: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,欢送分割咱们

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理