diff --git a/Source/Orleans.StorageProviderInterceptors/Abstractions/INamedStorageInterceptorFactory.cs b/Source/Orleans.StorageProviderInterceptors/Abstractions/INamedStorageInterceptorFactory.cs index f49cf06..4bbf40a 100644 --- a/Source/Orleans.StorageProviderInterceptors/Abstractions/INamedStorageInterceptorFactory.cs +++ b/Source/Orleans.StorageProviderInterceptors/Abstractions/INamedStorageInterceptorFactory.cs @@ -13,5 +13,5 @@ public interface INamedStorageInterceptorFactory /// /// /// - IPersistentState Create(IGrainActivationContext context, IStorageInterceptorConfig config); + IPersistentState Create(IGrainContext context, IStorageInterceptorConfig config); } diff --git a/Source/Orleans.StorageProviderInterceptors/Abstractions/IStorageInterceptorConfig.cs b/Source/Orleans.StorageProviderInterceptors/Abstractions/IStorageInterceptorConfig.cs index e9b2827..ab71986 100644 --- a/Source/Orleans.StorageProviderInterceptors/Abstractions/IStorageInterceptorConfig.cs +++ b/Source/Orleans.StorageProviderInterceptors/Abstractions/IStorageInterceptorConfig.cs @@ -29,7 +29,7 @@ public interface IStorageInterceptorFullConfig : IStorageInterceptorConf /// /// . /// - IGrainActivationContext Context { get; set; } + IGrainContext Context { get; set; } /// /// . /// @@ -58,7 +58,7 @@ public StorageInterceptorFullConfig(string stateName, string storageName) /// /// . /// - public IGrainActivationContext Context { get; set; } = default!; + public IGrainContext Context { get; set; } = default!; /// /// . /// diff --git a/Source/Orleans.StorageProviderInterceptors/Abstractions/IStorageInterceptorFactory.cs b/Source/Orleans.StorageProviderInterceptors/Abstractions/IStorageInterceptorFactory.cs index 24d36f0..538ffd2 100644 --- a/Source/Orleans.StorageProviderInterceptors/Abstractions/IStorageInterceptorFactory.cs +++ b/Source/Orleans.StorageProviderInterceptors/Abstractions/IStorageInterceptorFactory.cs @@ -16,5 +16,5 @@ public interface IStorageInterceptorFactory /// /// /// - IStorageInterceptor Create(IGrainActivationContext context, IStorageInterceptorConfig config, string fullStateName, IGrainStorage storageProvider); + IStorageInterceptor Create(IGrainContext context, IStorageInterceptorConfig config, string fullStateName, IGrainStorage storageProvider); } diff --git a/Source/Orleans.StorageProviderInterceptors/Infrastructure/NamedStorageInterceptorFactory.cs b/Source/Orleans.StorageProviderInterceptors/Infrastructure/NamedStorageInterceptorFactory.cs index bc591c8..011d96c 100644 --- a/Source/Orleans.StorageProviderInterceptors/Infrastructure/NamedStorageInterceptorFactory.cs +++ b/Source/Orleans.StorageProviderInterceptors/Infrastructure/NamedStorageInterceptorFactory.cs @@ -6,11 +6,9 @@ namespace Orleans.StorageProviderInterceptors.Infrastructure; using Orleans; using Orleans.Runtime; using Orleans.Storage; -using Orleans.Utilities; using Orleans.StorageProviderInterceptors.Abstractions; -using System.Text; -using System.Collections.Concurrent; using Orleans.Hosting; +using Orleans.Serialization.TypeSystem; /// /// TODO @@ -30,7 +28,7 @@ public class NamedStorageInterceptorFactory : INamedStorageInterceptorFactory /// /// /// - public IPersistentState Create(IGrainActivationContext context, IStorageInterceptorConfig config) + public IPersistentState Create(IGrainContext context, IStorageInterceptorConfig config) { //var factory = string.IsNullOrEmpty(config.StorageName) // ? this.services.GetService() @@ -64,13 +62,12 @@ public IPersistentState Create(IGrainActivationContext context, /// /// /// - protected virtual string GetFullStateName(IGrainActivationContext context, IStorageInterceptorConfig cfg) => $"{RuntimeTypeNameFormatter.Format(context.GrainType)}.{cfg.StateName}"; - internal static TypeFormattingOptions LogFormat { get; } = new TypeFormattingOptions(includeGlobal: false); + protected virtual string GetFullStateName(IGrainContext context, IStorageInterceptorConfig cfg) => $"{RuntimeTypeNameFormatter.Format(context.GrainInstance!.GetType())}.{cfg.StateName}"; - private static void ThrowMissingProviderException(IGrainActivationContext context, IStorageInterceptorConfig cfg) + private static void ThrowMissingProviderException(IGrainContext context, IStorageInterceptorConfig cfg) { string errMsg; - var grainTypeName = BuildParseableName(context.GrainType); + var grainTypeName = context.GrainInstance!.GetType(); if (string.IsNullOrEmpty(cfg.StorageName)) { errMsg = $"No default storage provider found loading grain type {grainTypeName}."; @@ -80,22 +77,7 @@ private static void ThrowMissingProviderException(IGrainActivationContext contex errMsg = $"No storage provider named \"{cfg.StorageName}\" found loading grain type {grainTypeName}."; } - throw new BadGrainStorageConfigException(errMsg); - } - - private static string BuildParseableName(Type type) - { - var builder = new StringBuilder(); - GetParseableName( - type, - builder, - new Queue( - type.IsGenericTypeDefinition - ? type.GetGenericArguments() - : type.GenericTypeArguments), - LogFormat, - t => GetUnadornedTypeName(t) + LogFormat.NameSuffix); - return builder.ToString(); + throw new InvalidOperationException(errMsg); } /// @@ -114,159 +96,20 @@ public static string GetUnadornedTypeName(Type type) // An ampersand can appear as a suffix to a by-ref type. return (index > 0 ? type.Name[..index] : type.Name).TrimEnd('&'); } - internal static TypeFormattingOptions Default { get; } = new TypeFormattingOptions(); - private static readonly ConcurrentDictionary, string> ParseableNameCache = new(); private readonly IServiceProvider services; - internal static string GetParseableName(Type type, TypeFormattingOptions? options = null, Func? getNameFunc = null) - { - options ??= Default; - - // If a naming function has been specified, skip the cache. - if (getNameFunc != null) - { - return BuildParseableName(); - } - - return ParseableNameCache.GetOrAdd(Tuple.Create(type, options), _ => BuildParseableName()); - - string BuildParseableName() - { - var builder = new StringBuilder(); - GetParseableName( - type, - builder, - new Queue( - type.IsGenericTypeDefinition - ? type.GetGenericArguments() - : type.GenericTypeArguments), - options, - t => GetUnadornedTypeName(t) + options.NameSuffix); - return builder.ToString(); - } - } - /// Returns a string representation of . - /// The type. - /// The to append results to. - /// The type arguments of . - /// The type formatting options. - /// Delegate that returns name for a type. - private static void GetParseableName( - Type type, - StringBuilder builder, - Queue typeArguments, - TypeFormattingOptions options, - Func getNameFunc) - { - if (type.IsArray) - { - var elementType = GetParseableName(type.GetElementType()!, options); - if (!string.IsNullOrWhiteSpace(elementType)) - { - _ = builder.Append(elementType).Append('[').Append(new string(',', type.GetArrayRank() - 1)).Append(']'); - } - - return; - } - - if (type.IsGenericParameter) - { - if (options.IncludeGenericTypeParameters) - { - builder.Append(GetUnadornedTypeName(type)); - } - - return; - } - - if (type.DeclaringType != null) - { - // This is not the root type. - GetParseableName(type.DeclaringType, builder, typeArguments, options, t => GetUnadornedTypeName(t)); - builder.Append(options.NestedTypeSeparator); - } - else if (!string.IsNullOrWhiteSpace(type.Namespace) && options.IncludeNamespace) - { - // This is the root type, so include the namespace. - var namespaceName = type.Namespace; - if (options.NestedTypeSeparator != '.') - { - namespaceName = namespaceName.Replace('.', options.NestedTypeSeparator); - } - - if (options.IncludeGlobal) - { - builder.Append("global::"); - } - - builder.Append(namespaceName).Append(options.NestedTypeSeparator); - } - - if (type.IsConstructedGenericType) - { - // Get the unadorned name, the generic parameters, and add them together. - var unadornedTypeName = getNameFunc(type); - builder.Append(EscapeIdentifier(unadornedTypeName)); - var generics = - Enumerable.Range(0, Math.Min(type.GetGenericArguments().Length, typeArguments.Count)) - .Select(_ => typeArguments.Dequeue()) - .ToList(); - if (generics.Count > 0 && options.IncludeTypeParameters) - { - var genericParameters = string.Join( - ",", - generics.Select(generic => GetParseableName(generic, options))); - builder.Append('<').Append(genericParameters).Append('>'); - } - } - else if (type.IsGenericTypeDefinition) - { - // Get the unadorned name, the generic parameters, and add them together. - var unadornedTypeName = getNameFunc(type); - builder.Append(EscapeIdentifier(unadornedTypeName)); - var generics = - Enumerable.Range(0, Math.Min(type.GetGenericArguments().Length, typeArguments.Count)) - .Select(_ => typeArguments.Dequeue()) - .ToList(); - if (generics.Count > 0 && options.IncludeTypeParameters) - { - var genericParameters = string.Join( - ",", - generics.Select(_ => options.IncludeGenericTypeParameters ? _.ToString() : string.Empty)); - builder.Append('<').Append(genericParameters).Append('>'); - } - } - else - { - builder.Append(EscapeIdentifier(getNameFunc(type))); - } - } - private static string EscapeIdentifier(string identifier) - { - if (IsCSharpKeyword(identifier)) - { - return "@" + identifier; - } - - return identifier; - } - internal static bool IsCSharpKeyword(string identifier) => identifier switch - { - "abstract" or "add" or "alias" or "as" or "ascending" or "async" or "await" or "base" or "bool" or "break" or "byte" or "case" or "catch" or "char" or "checked" or "class" or "const" or "continue" or "decimal" or "default" or "delegate" or "descending" or "do" or "double" or "dynamic" or "else" or "enum" or "event" or "explicit" or "extern" or "false" or "finally" or "fixed" or "float" or "for" or "foreach" or "from" or "get" or "global" or "goto" or "group" or "if" or "implicit" or "in" or "int" or "interface" or "internal" or "into" or "is" or "join" or "let" or "lock" or "long" or "nameof" or "namespace" or "new" or "null" or "object" or "operator" or "orderby" or "out" or "override" or "params" or "partial" or "private" or "protected" or "public" or "readonly" or "ref" or "remove" or "return" or "sbyte" or "sealed" or "select" or "set" or "short" or "sizeof" or "stackalloc" or "static" or "string" or "struct" or "switch" or "this" or "throw" or "true" or "try" or "typeof" or "uint" or "ulong" or "unchecked" or "unsafe" or "ushort" or "using" or "value" or "var" or "virtual" or "void" or "volatile" or "when" or "where" or "while" or "yield" => true, - _ => false, - }; /// - public IPersistentState Create(IGrainActivationContext context, IStorageInterceptorFullConfig config) => throw new NotImplementedException(); + public IPersistentState Create(IGrainContext context, IStorageInterceptorFullConfig config) => throw new NotImplementedException(); private sealed class PersistentStateBridge : IPersistentState, ILifecycleParticipant { private readonly string fullStateName; - private readonly IGrainActivationContext context; + private readonly IGrainContext context; private readonly IGrainStorage storageProvider; private readonly StorageInterceptorOptions options; - private IStorage storage = default!; + private StateStorageBridge storage = default!; - public PersistentStateBridge(string fullStateName, IGrainActivationContext context, IGrainStorage storageProvider, StorageInterceptorOptions options) + public PersistentStateBridge(string fullStateName, IGrainContext context, IGrainStorage storageProvider, StorageInterceptorOptions options) { ArgumentNullException.ThrowIfNull(fullStateName); ArgumentNullException.ThrowIfNull(context); @@ -285,7 +128,7 @@ public TState State set => this.storage.State = value; } - public string Etag => this.storage.Etag; + public string? Etag => this.storage.Etag; public bool RecordExists => this.storage.RecordExists; @@ -331,7 +174,7 @@ private Task OnSetupState(CancellationToken ct) return Task.CompletedTask; } - this.storage = new StateStorageBridge(this.fullStateName, this.context.GrainInstance.GrainReference, this.storageProvider, this.context.ActivationServices.GetService()); + this.storage = new StateStorageBridge(this.fullStateName, this.context, this.storageProvider, this.context.ActivationServices.GetRequiredService()); return this.ReadStateAsync(); } } diff --git a/Source/Orleans.StorageProviderInterceptors/Infrastructure/StorageInterceptorAttributeMapper.cs b/Source/Orleans.StorageProviderInterceptors/Infrastructure/StorageInterceptorAttributeMapper.cs index 0707535..e39ddc7 100644 --- a/Source/Orleans.StorageProviderInterceptors/Infrastructure/StorageInterceptorAttributeMapper.cs +++ b/Source/Orleans.StorageProviderInterceptors/Infrastructure/StorageInterceptorAttributeMapper.cs @@ -17,7 +17,7 @@ public class StorageInterceptorAttributeMapper : IAttributeToFactoryMapper /// /// - public Factory GetFactory(ParameterInfo parameter, StorageInterceptorAttribute metadata) + public Factory GetFactory(ParameterInfo parameter, StorageInterceptorAttribute metadata) { ArgumentNullException.ThrowIfNull(parameter); IStorageInterceptorConfig config = metadata; @@ -30,7 +30,7 @@ public Factory GetFactory(ParameterInfo paramet return context => Create(context, genericCreate, config); } - private static object Create(IGrainActivationContext context, MethodInfo genericCreate, IStorageInterceptorConfig config) + private static object Create(IGrainContext context, MethodInfo genericCreate, IStorageInterceptorConfig config) { var factory = context.ActivationServices.GetRequiredService(); var args = new object[] { context, config }; diff --git a/Source/Orleans.StorageProviderInterceptors/Infrastructure/StorageInterceptorOptions.cs b/Source/Orleans.StorageProviderInterceptors/Infrastructure/StorageInterceptorOptions.cs index 281fafd..972a91b 100644 --- a/Source/Orleans.StorageProviderInterceptors/Infrastructure/StorageInterceptorOptions.cs +++ b/Source/Orleans.StorageProviderInterceptors/Infrastructure/StorageInterceptorOptions.cs @@ -10,30 +10,30 @@ public class StorageInterceptorOptions /// /// Called before a ClearStateAsync(); return false to prevent writing. /// - public Func, ValueTask<(bool PreventOperation, object? SharedState)>> OnBeforeClearStateAsync { get; set; } = (_, _) => ValueTask.FromResult((false, (object?)null)); + public Func, ValueTask<(bool PreventOperation, object? SharedState)>> OnBeforeClearStateAsync { get; set; } = (_, _) => ValueTask.FromResult((false, (object?)null)); /// /// Called after ClearStateAsync(); /// - public Func, object?, ValueTask> OnAfterClearStateAsync { get; set; } = (_, _, _) => ValueTask.CompletedTask; + public Func, object?, ValueTask> OnAfterClearStateAsync { get; set; } = (_, _, _) => ValueTask.CompletedTask; /// /// Called before ReadStateAsync(); return false to prevent Reading /// - public Func, ValueTask<(bool PreventOperation, object? SharedState)>> OnBeforeReadStateAsync { get; set; } = (_, _) => ValueTask.FromResult((false, (object?)null)); + public Func, ValueTask<(bool PreventOperation, object? SharedState)>> OnBeforeReadStateAsync { get; set; } = (_, _) => ValueTask.FromResult((false, (object?)null)); /// /// Called after ReadStateAsync() /// - public Func, object?, ValueTask> OnAfterReadStateFunc { get; set; } = (_, _, _) => ValueTask.CompletedTask; + public Func, object?, ValueTask> OnAfterReadStateFunc { get; set; } = (_, _, _) => ValueTask.CompletedTask; /// /// Called before WriteStateAsync(); return false to prevent writing /// - public Func, ValueTask<(bool PreventOperation, object? SharedState)>> OnBeforeWriteStateFunc { get; set; } = (_, _) => ValueTask.FromResult((false, (object?)null)); + public Func, ValueTask<(bool PreventOperation, object? SharedState)>> OnBeforeWriteStateFunc { get; set; } = (_, _) => ValueTask.FromResult((false, (object?)null)); /// /// Called after WriteStateAsync() /// - public Func, object?, ValueTask> OnAfterWriteStateFunc { get; set; } = (_, _, _) => ValueTask.CompletedTask; + public Func, object?, ValueTask> OnAfterWriteStateFunc { get; set; } = (_, _, _) => ValueTask.CompletedTask; } diff --git a/Source/Orleans.StorageProviderInterceptors/Interceptors/GenericStorageInterceptorFactory.cs b/Source/Orleans.StorageProviderInterceptors/Interceptors/GenericStorageInterceptorFactory.cs index 35586e3..425a3e1 100644 --- a/Source/Orleans.StorageProviderInterceptors/Interceptors/GenericStorageInterceptorFactory.cs +++ b/Source/Orleans.StorageProviderInterceptors/Interceptors/GenericStorageInterceptorFactory.cs @@ -10,14 +10,14 @@ ///// //public class GenericStorageInterceptorFactory : IStorageInterceptorFactory //{ -// private readonly IGrainActivationContext context; +// private readonly IGrainContext context; // /// // /// TODO // /// // /// -// public GenericStorageInterceptorFactory(IGrainActivationContext context) => this.context = context; +// public GenericStorageInterceptorFactory(IGrainContext context) => this.context = context; // /// -// public IStorageInterceptor Create(IGrainActivationContext context, IStorageInterceptorConfig config, string fullStateName, IGrainStorage storageProvider) +// public IStorageInterceptor Create(IGrainContext context, IStorageInterceptorConfig config, string fullStateName, IGrainStorage storageProvider) // { // var storage = this.context.ActivationServices.GetRequiredService>(); // var options = this.context.ActivationServices.GetRequiredServiceByName>(config.StorageName); diff --git a/Source/Orleans.StorageProviderInterceptors/Orleans.StorageProviderInterceptors.csproj b/Source/Orleans.StorageProviderInterceptors/Orleans.StorageProviderInterceptors.csproj index 6852eb0..5fd758e 100644 --- a/Source/Orleans.StorageProviderInterceptors/Orleans.StorageProviderInterceptors.csproj +++ b/Source/Orleans.StorageProviderInterceptors/Orleans.StorageProviderInterceptors.csproj @@ -1,7 +1,7 @@ - net6.0 + net7.0 @@ -11,8 +11,16 @@ - - + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + diff --git a/Source/Sample/Program.cs b/Source/Sample/Program.cs index f6c5312..2fc4652 100644 --- a/Source/Sample/Program.cs +++ b/Source/Sample/Program.cs @@ -1,9 +1,6 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; -using Orleans; -using Orleans.Configuration; -using Orleans.Hosting; using Orleans.Runtime; using Orleans.StorageProviderInterceptors.Abstractions; using Sample; @@ -13,8 +10,6 @@ var host = Host.CreateDefaultBuilder() .UseOrleans(builder => builder .UseLocalhostClustering() - //Quiet down the silo for the demo. - .Configure(c => c.CollectionLevel = Orleans.Runtime.Configuration.StatisticsLevel.Critical) .ConfigureLogging(c => c.SetMinimumLevel(LogLevel.None)) .AddMemoryGrainStorage("SecretsStorage") .AddStorageInterceptors() @@ -24,7 +19,7 @@ c.OnBeforeWriteStateFunc = (grainActivationContext, currentState) => { var unencryptedValues = new Dictionary(currentState.State.Count); - Console.WriteLine($"OnBeforeWriteState: {grainActivationContext.GrainIdentity.IdentityString}: Count Is {currentState.State.Count}"); + Console.WriteLine($"OnBeforeWriteState: {grainActivationContext}: Count Is {currentState.State.Count}"); foreach (var (key, value) in currentState.State) { Console.WriteLine($"Intercepted: {key}: {value}"); @@ -41,7 +36,7 @@ c.OnAfterWriteStateFunc = (grainActivationContext, currentState, sharedState) => { var unencryptedValues = (Dictionary)sharedState!; - Console.WriteLine($"OnAfterWriteState: {grainActivationContext.GrainIdentity.IdentityString}: Count Is {currentState.State.Count}"); + Console.WriteLine($"OnAfterWriteState: {grainActivationContext}: Count Is {currentState.State.Count}"); foreach (var (key, value) in currentState.State) { Console.WriteLine($"What was actually persisted: {key}: {value}"); @@ -54,7 +49,7 @@ c.OnBeforeReadStateAsync = (grainActivationContext, currentState) => { - Console.WriteLine($"OnBeforeReadState: {grainActivationContext.GrainIdentity.IdentityString}: Count Is {currentState.State.Count}"); + Console.WriteLine($"OnBeforeReadState: {grainActivationContext}: Count Is {currentState.State.Count}"); var unencryptedValues = new Dictionary(currentState.State.Count); foreach (var (key, value) in currentState.State) @@ -76,7 +71,7 @@ } var list = sharedState as List; - Console.WriteLine($"OnAfterReadState: {grainActivationContext.GrainIdentity.IdentityString}: Count Is {currentState.State.Count}"); + Console.WriteLine($"OnAfterReadState: {grainActivationContext}: Count Is {currentState.State.Count}"); foreach (var (key, value) in currentState.State) { @@ -120,7 +115,7 @@ namespace Sample { - internal class SecretStorageGrain : Grain, ISecretStorageGrain + internal sealed class SecretStorageGrain : Grain, ISecretStorageGrain { private readonly IPersistentState> secrets; diff --git a/Source/Sample/Sample.csproj b/Source/Sample/Sample.csproj index 9069bef..e2cf00e 100644 --- a/Source/Sample/Sample.csproj +++ b/Source/Sample/Sample.csproj @@ -2,20 +2,19 @@ Exe - net6.0 + net7.0 false - - - - + + + + - - - - + + + all runtime; build; native; contentfiles; analyzers @@ -24,4 +23,13 @@ + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + diff --git a/Tests/Orleans.StorageProviderInterceptors.Test/Class1Test.cs b/Tests/Orleans.StorageProviderInterceptors.Test/Class1Test.cs index 633c738..dedfe94 100644 --- a/Tests/Orleans.StorageProviderInterceptors.Test/Class1Test.cs +++ b/Tests/Orleans.StorageProviderInterceptors.Test/Class1Test.cs @@ -2,8 +2,14 @@ namespace Orleans.StorageProviderInterceptors.Test; using Xunit; +/// +/// Class1 test +/// public class Class1Test { + /// + /// Given when true + /// [Fact] public void Given_When_Then() => Assert.True(true); } diff --git a/Tests/Orleans.StorageProviderInterceptors.Test/Orleans.StorageProviderInterceptors.Test.csproj b/Tests/Orleans.StorageProviderInterceptors.Test/Orleans.StorageProviderInterceptors.Test.csproj index d64baf5..59d8f01 100644 --- a/Tests/Orleans.StorageProviderInterceptors.Test/Orleans.StorageProviderInterceptors.Test.csproj +++ b/Tests/Orleans.StorageProviderInterceptors.Test/Orleans.StorageProviderInterceptors.Test.csproj @@ -1,11 +1,32 @@ - net6.0 + net7.0 + true + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + +