升级指南
官方升级指南
https://learn.microsoft.com/zh-cn/dotnet/orleans/migration-guide?source=recommendations
主要涉及以下几个改动点
- ConfigureApplicationParts
3.6.5版在Silo初始化的时候,会通过这个方法将指定目录下的Grain加载进来
.ConfigureApplicationParts(parts => parts.AddFromApplicationBaseDirectory())
8.0.0版就不需要了,直接去掉这个方法,因为它有另外新的加载机制,后面会说到
- JsonGrainStateSerializerOptions
3.6.5版的Grain状态消息Json序列化配置,是在Silo初始化时(比如使用MongoDB作为持久化存储)通过ConfigureJsonSerializerSettings配置的
.AddMongoDBGrainStorage("Default", (MongoDBGrainStorageOptions op) => { op.CollectionPrefix = "GrainStorage"; op.DatabaseName = configSection.GetValue<string>("DataBase"); op.ConfigureJsonSerializerSettings = jsonSettings => { jsonSettings.NullValueHandling = NullValueHandling.Include; jsonSettings.DefaultValueHandling = DefaultValueHandling.Populate; jsonSettings.ObjectCreationHandling = ObjectCreationHandling.Replace; }; })
8.0.0版的Grain状态消息Json序列化配置,是在Silo初始化时通过配置JsonGrainStateSerializerOptions属性
.Configure<JsonGrainStateSerializerOptions>(options => options.ConfigureJsonSerializerSettings = settings => { settings.NullValueHandling = NullValueHandling.Include; settings.ObjectCreationHandling = ObjectCreationHandling.Replace; settings.DefaultValueHandling = DefaultValueHandling.Populate; })
但仅仅这个还不够,还需要单独实现一个Grain状态的序列化器(因为8.0.3版的Orleans.Providers.MongoDB包有Bug所以才需要这一步,这个Bug已经由我向作者反馈过,详情见https://github.com/OrleansContrib/Orleans.Providers.MongoDB/issues/136,包的作者也修复了,后续新的版本应该不用),如下
public class NewJsonGrainStateSerializer: IGrainStateSerializer { private readonly JsonSerializerSettings jsonSettings; public NewJsonGrainStateSerializer(IOptions<JsonGrainStateSerializerOptions> options, IServiceProvider serviceProvider) { jsonSettings = OrleansJsonSerializerSettings.GetDefaultSerializerSettings(serviceProvider); options.Value.ConfigureJsonSerializerSettings(jsonSettings); } public T Deserialize<T>(BsonValue value) { using var jsonReader = new JTokenReader(value.ToJToken()); var localSerializer = JsonSerializer.CreateDefault(jsonSettings); return localSerializer.Deserialize<T>(jsonReader); } public BsonValue Serialize<T>(T state) { var localSerializer = JsonSerializer.CreateDefault(jsonSettings); return JObject.FromObject(state, localSerializer).ToBson(); } }
并将NewJsonGrainStateSerializer注入到容器替换掉默认的序列化器
.ConfigureServices(services => services.AddSingleton<IGrainStateSerializer,NewJsonGrainStateSerializer>())
- AddSimpleMessageStreamProvider
3.6.5版中如果你使用了流式订阅,且用的是
SimpleMessageStreams
(也称为 SMS).AddSimpleMessageStreamProvider(ApplicationConsts.MessageStreamName)
8.0.0版中需要将它替换为使用MemoryStream
.AddMemoryStreams(AeFinderApplicationConsts.MessageStreamName)
- UseOrleansClient
3.6.5版初始化Orleans的客户端,是通过给IClusterClient注册一个ClientBuilder对象,如下:
context.Services.AddSingleton<IClusterClient>(o => { return new ClientBuilder() .ConfigureDefaults() // .UseRedisClustering(opt => // { // opt.ConnectionString = configuration["Orleans:ClusterDbConnection"]; // opt.Database = Convert.ToInt32(configuration["Orleans:ClusterDbNumber"]); // }) .UseMongoDBClient(configuration["Orleans:MongoDBClient"]) .UseMongoDBClustering(options => { options.DatabaseName = configuration["Orleans:DataBase"];; options.Strategy = MongoDBMembershipStrategy.SingleDocument; }) .Configure<ClusterOptions>(options => { options.ClusterId = configuration["Orleans:ClusterId"]; options.ServiceId = configuration["Orleans:ServiceId"]; }) .ConfigureApplicationParts(parts => parts.AddApplicationPart(typeof(GrainsModule).Assembly).WithReferences()) .AddSimpleMessageStreamProvider(ApplicationConsts.MessageStreamName) .ConfigureLogging(builder => builder.AddProvider(o.GetService<ILoggerProvider>())) .Build(); });
8.0.0版就得换一种方式了,它直接提供了UseOrleansClient扩展方法来帮助你实现,如下:
public static IHostBuilder UseOrleansClient(this IHostBuilder hostBuilder) { return hostBuilder.UseOrleansClient((context, clientBuilder) => { var configSection = context.Configuration.GetSection("Orleans"); if (configSection == null) throw new ArgumentNullException(nameof(configSection), "The Orleans config node is missing"); clientBuilder.UseMongoDBClient(configSection.GetValue<string>("MongoDBClient")) .UseMongoDBClustering(options => { options.DatabaseName = configSection.GetValue<string>("DataBase"); options.Strategy = MongoDBMembershipStrategy.SingleDocument; }) .Configure<ClusterOptions>(options => { options.ClusterId = configSection.GetValue<string>("ClusterId"); options.ServiceId = configSection.GetValue<string>("ServiceId"); }) .AddMemoryStreams(AeFinderApplicationConsts.MessageStreamName) .AddActivityPropagation(); }); }
- GenerateSerializer
3.6.5版的Grain类加载,是通过上面说到的ConfigureApplicationParts方法
8.0.0版不用,它会自动寻找那些引用了Microsoft.Orleans.Sdk包的程序集,找出里面的Grain类自动进行加载到Silo中
除此之外,它还需要你给每个Grain中定义的方法用到的通信类(输入和输出),都标上【GenerateSerializer】和【Id】注解,如下:
[GenerateSerializer] public class CreateAppDto { [Id(0)] public string AppId { get; set; } [Id(1)] public string OrganizationId { get; set; } [Id(2)] public string DeployKey { get; set; } [MinLength(2),MaxLength(20)] [RegularExpression("[A-Za-z0-9\\s]+" ,ErrorMessage = "The AppName can only contain letters('A'-'Z', 'a'-'z'), numbers(0-9), and spaces(' ').")] [Id(3)] public string AppName { get; set; } }
- OnActivateAsync
3.6.5版中关于Grain激活和失活过程的重载方法分别是
public override async Task OnActivateAsync() { await ReadStateAsync(); await base.OnActivateAsync(); } public override async Task OnDeactivateAsync() { await WriteStateAsync(); await base.OnDeactivateAsync(); }
8.0.0版中关于Grain激活和失活过程的重载方法分别是
public override async Task OnActivateAsync(CancellationToken cancellationToken) { await ReadStateAsync(); await base.OnActivateAsync(cancellationToken); } public override async Task OnDeactivateAsync(DeactivationReason reason, CancellationToken cancellationToken) { await WriteStateAsync(); await base.OnDeactivateAsync(reason, cancellationToken); }
主要是多了一些入参
注意
我这里只是列了一些主要的改动点,实际升级过程中需要注意的其他地方可以参考官方文档。
此博客为作者原创,转载请注明出处,谢谢~