Esempio n. 1
0
        /// <summary>
        /// Initializes a new instance of the <see cref="SerializerConfigurationValidator"/> class.
        /// </summary>
        /// <param name="codecProvider">
        /// The codec provider.
        /// </param>
        /// <param name="options">
        /// The type manifest options.
        /// </param>
        /// <param name="serviceProvider">
        /// The service provider.
        /// </param>
        public SerializerConfigurationValidator(ICodecProvider codecProvider, IOptions <TypeManifestOptions> options, IServiceProvider serviceProvider)
        {
            _codecProvider = codecProvider;
            _options       = options.Value;

            var configEnabled = _options.EnableConfigurationAnalysis;

            if (configEnabled.HasValue)
            {
                _enabled = configEnabled.Value;
            }
            else
            {
                // Enable in development envioronment by default.
                var environment = serviceProvider.GetService <IHostEnvironment>();
                _enabled = environment is not null && environment.IsDevelopment();
            }
        }
        /// <summary>
        /// Analyzes grain interface methods to find parameter types and return types which are not serializable.
        /// </summary>
        /// <param name="codecProvider">
        /// The codec provider.
        /// </param>
        /// <param name="options">
        /// The type manifest options.
        /// </param>
        /// <returns>
        /// A collection of types which have serializability issues.
        /// </returns>
        public static Dictionary <Type, SerializerConfigurationComplaint> AnalyzeSerializerAvailability(ICodecProvider codecProvider, TypeManifestOptions options)
        {
            var allComplaints = new Dictionary <Type, SerializerConfigurationComplaint>();

            foreach (var @interface in options.Interfaces)
            {
                foreach (var method in @interface.GetMethods())
                {
                    if (typeof(Task).IsAssignableFrom(method.ReturnType))
                    {
                        if (method.ReturnType.IsConstructedGenericType && typeof(Task <>).IsAssignableFrom(method.ReturnType.GetGenericTypeDefinition()))
                        {
                            VisitType(method.ReturnType.GetGenericArguments()[0], method);
                        }
                    }

                    if (method.ReturnType.IsConstructedGenericType && typeof(ValueTask <>).IsAssignableFrom(method.ReturnType.GetGenericTypeDefinition()))
                    {
                        VisitType(method.ReturnType.GetGenericArguments()[0], method);
                    }

                    foreach (var param in method.GetParameters())
                    {
                        VisitType(param.ParameterType, method);
                    }
                }
            }

            return(allComplaints);

            void VisitType(Type type, MethodInfo methodInfo)
            {
                if (!IsEligibleType(type))
                {
                    return;
                }

                var hasCodec  = codecProvider.TryGetCodec(type) is not null;
                var hasCopier = codecProvider.TryGetDeepCopier(type) is not null;

                if (!hasCodec || !hasCopier)
                {
                    if (!allComplaints.TryGetValue(type, out var complaint))
                    {
                        complaint = allComplaints[type] = new()
                        {
                            HasSerializer = hasCodec,
                            HasCopier     = hasCopier,
                        };
                    }

                    if (!complaint.Methods.TryGetValue(methodInfo.DeclaringType, out var methodList))
                    {
                        methodList = complaint.Methods[methodInfo.DeclaringType] = new HashSet <MethodInfo>();
                    }

                    methodList.Add(methodInfo);
                }
            }

            bool IsEligibleType(Type type)
            {
                if (type.IsGenericTypeParameter || type.IsGenericMethodParameter || type.ContainsGenericParameters)
                {
                    return(false);
                }

                return(true);
            }
        }