コード例 #1
0
        public void GenerateDocument_GeneratesDocumentWithSingleMessage()
        {
            // Arrange
            var options           = new AsyncApiOptions();
            var schemaGenerator   = new SchemaGenerator(Options.Create(options));
            var documentGenerator = new DocumentGenerator(Options.Create(options), schemaGenerator);

            // Act
            var document = documentGenerator.GenerateDocument(new [] { typeof(TenantSingleMessagePublisher).GetTypeInfo() });

            // Assert
            document.ShouldNotBeNull();
            document.Channels.Count.ShouldBe(1);

            var channel = document.Channels.First();

            channel.Key.ShouldBe("asw.tenant_service.tenants_history");
            channel.Value.Description.ShouldBe("Tenant events.");

            var publish = channel.Value.Publish;

            publish.ShouldNotBeNull();
            publish.OperationId.ShouldBe("TenantSingleMessagePublisher");
            publish.Summary.ShouldBe("Publish single domain event about tenants.");

            var message = publish.Message.ShouldBeOfType <Message>();

            message.Name.ShouldBe("anyTenantCreated");
        }
コード例 #2
0
        public SchemaGenerationTests()
        {
            _schemaRepository = new SchemaRepository();
            var options = new AsyncApiOptions();

            _schemaGenerator = new SchemaGenerator(Options.Create(options));
        }
コード例 #3
0
        public static bool TryGetDocument(this HttpContext context, AsyncApiOptions options, out string document)
        {
            document = null;
#if NETSTANDARD2_0
            var template = TemplateParser.Parse(options.Middleware.Route);

            var values  = new RouteValueDictionary();
            var matcher = new TemplateMatcher(template, values);
            if (!matcher.TryMatch(context.Request.Path, values))
            {
                template = TemplateParser.Parse(options.Middleware.UiBaseRoute + "{*wildcard}");
                matcher  = new TemplateMatcher(template, values);
                matcher.TryMatch(context.Request.Path, values);
            }
#else
            var values = context.Request.RouteValues;
#endif
            if (!values.TryGetValue("document", out var value))
            {
                return(false);
            }

            document = value.ToString();
            return(true);
        }
コード例 #4
0
        public void GenerateDocument_GeneratesDocumentWithMultipleMessagesPerChannel()
        {
            // Arrange
            var options           = new AsyncApiOptions();
            var documentGenerator = new DocumentGenerator();

            // Act
            var document = documentGenerator.GenerateDocument(new [] { typeof(TenantMessagePublisher).GetTypeInfo() }, options, options.AsyncApi, ActivatorServiceProvider.Instance);

            // Assert
            document.ShouldNotBeNull();
            document.Channels.Count.ShouldBe(1);

            var channel = document.Channels.First();

            channel.Key.ShouldBe("asw.tenant_service.tenants_history");
            channel.Value.Description.ShouldBe("Tenant events.");

            var publish = channel.Value.Publish;

            publish.ShouldNotBeNull();
            publish.OperationId.ShouldBe("TenantMessagePublisher");
            publish.Summary.ShouldBe("Publish domains events about tenants.");

            var messages = publish.Message.ShouldBeOfType <Messages>();

            messages.OneOf.Count.ShouldBe(3);

            messages.OneOf.OfType <MessageReference>().ShouldContain(m => m.Id == "anyTenantCreated");
            messages.OneOf.OfType <MessageReference>().ShouldContain(m => m.Id == "anyTenantUpdated");
            messages.OneOf.OfType <MessageReference>().ShouldContain(m => m.Id == "anyTenantRemoved");
        }
コード例 #5
0
        public void GenerateDocument_GeneratesDocumentWithChannelParameters()
        {
            // Arrange
            var options           = new AsyncApiOptions();
            var documentGenerator = new DocumentGenerator();

            // Act
            var document = documentGenerator.GenerateDocument(new [] { typeof(OneTenantMessageConsumer).GetTypeInfo() }, options, options.AsyncApi, ActivatorServiceProvider.Instance);

            // Assert
            document.ShouldNotBeNull();
            document.Channels.Count.ShouldBe(1);

            var channel = document.Channels.First();

            channel.Key.ShouldBe("asw.tenant_service.{tenant_id}.{tenant_status}");
            channel.Value.Description.ShouldBe("A tenant events.");
            channel.Value.Parameters.Count.ShouldBe(2);
            channel.Value.Parameters.Values.OfType <ParameterReference>().ShouldContain(p => p.Id == "tenant_id" && p.Value.Schema != null && p.Value.Description == "The tenant identifier.");
            channel.Value.Parameters.Values.OfType <ParameterReference>().ShouldContain(p => p.Id == "tenant_status" && p.Value.Schema != null && p.Value.Description == "The tenant status.");

            var subscribe = channel.Value.Subscribe;

            subscribe.ShouldNotBeNull();
            subscribe.OperationId.ShouldBe("OneTenantMessageConsumer");
            subscribe.Summary.ShouldBe("Subscribe to domains events about a tenant.");

            var messages = subscribe.Message.ShouldBeOfType <Messages>();

            messages.OneOf.Count.ShouldBe(3);

            messages.OneOf.OfType <MessageReference>().ShouldContain(m => m.Id == "tenantCreated");
            messages.OneOf.OfType <MessageReference>().ShouldContain(m => m.Id == "tenantUpdated");
            messages.OneOf.OfType <MessageReference>().ShouldContain(m => m.Id == "tenantRemoved");
        }
コード例 #6
0
 private static IEnumerable <string> GetEnumMemberNames(this Type type, AsyncApiOptions options)
 {
     foreach (Enum val in type.GetEnumValues())
     {
         yield return(options.EnumMemberNameSelector(type, val));
     }
 }
コード例 #7
0
        public void GetDocument_GeneratesDocumentWithMultipleMessagesPerChannel()
        {
            // Arrange
            var options           = new AsyncApiOptions();
            var schemaGenerator   = new SchemaGenerator(Options.Create(options));
            var documentGenerator = new DocumentGenerator(Options.Create(options), schemaGenerator);

            // Act
            var document = documentGenerator.GenerateDocument(new [] { typeof(TenantMessageConsumer).GetTypeInfo() });

            // Assert
            document.ShouldNotBeNull();
            document.Channels.Count.ShouldBe(1);

            var channel = document.Channels.First();

            channel.Key.ShouldBe("asw.tenant_service.tenants_history");
            channel.Value.Description.ShouldBe("Tenant events.");

            var subscribe = channel.Value.Subscribe;

            subscribe.ShouldNotBeNull();
            subscribe.OperationId.ShouldBe("TenantMessageConsumer");
            subscribe.Summary.ShouldBe("Subscribe to domains events about tenants.");

            var messages = subscribe.Message.ShouldBeOfType <Messages>();

            messages.OneOf.Count.ShouldBe(3);

            messages.OneOf.ShouldContain(m => m.Name == "tenantCreated");
            messages.OneOf.ShouldContain(m => m.Name == "tenantUpdated");
            messages.OneOf.ShouldContain(m => m.Name == "tenantRemoved");
        }
コード例 #8
0
        public void RouteTemplate_WhenNotSet_ReturnsDefaultValue()
        {
            const string defaultRouteTemplate = "async-api/async-api.{json|yaml}";

            var target = new AsyncApiOptions();

            Assert.AreEqual(defaultRouteTemplate, target.RouteTemplate);
        }
コード例 #9
0
        public void IsEnum_True_WhenTypeIsEnumMemberConverterEnum(Type type, string[] members)
        {
            var options = new AsyncApiOptions();

            type.IsEnum(options, out var actualMembers).ShouldBeTrue();
            actualMembers.MemberType.ShouldBe(typeof(string));
            actualMembers.Members.ShouldBe(members);
        }
コード例 #10
0
        public void IsEnum_True_WhenTypeIsEnum(Type type, int[] members)
        {
            var options = new AsyncApiOptions();

            type.IsEnum(options, out var actualMembers).ShouldBeTrue();
            actualMembers.MemberType.ShouldBe(typeof(int));
            actualMembers.Members.ShouldBe(members);
        }
コード例 #11
0
        /// <summary>
        /// Get all types with an <see cref="AsyncApiAttribute"/> from assemblies <see cref="AsyncApiOptions.AssemblyMarkerTypes"/>.
        /// </summary>
        private static TypeInfo[] GetAsyncApiTypes(AsyncApiOptions options, AsyncApiDocument prototype)
        {
            var assembliesToScan = options.AssemblyMarkerTypes.Select(t => t.Assembly);

            var asyncApiTypes = assembliesToScan
                                .SelectMany(a => a.DefinedTypes.Where(t => t.GetCustomAttribute <AsyncApiAttribute>()?.DocumentName == prototype.DocumentName))
                                .ToArray();

            return(asyncApiTypes);
        }
コード例 #12
0
        private static EnumMembers GetEnumMembers(this Type type, AsyncApiOptions options)
        {
            var useEnumName = options.UseEnumMemberName != null && options.UseEnumMemberName(type);

            if (useEnumName)
            {
                return(new EnumMembers(typeof(string), type.GetEnumMemberNames(options).ToList()));
            }

            return(new EnumMembers(typeof(int), type.GetEnumMemberValues().ToList()));
        }
コード例 #13
0
        public void RouteTemplate_WhenSet_ReturnsValue()
        {
            const string valueRouteTemplate = "some-route";

            var target = new AsyncApiOptions
            {
                RouteTemplate = valueRouteTemplate
            };

            Assert.AreEqual(valueRouteTemplate, target.RouteTemplate);
        }
コード例 #14
0
        public static IAsyncApiDocumentProvider Provider(Action <AsyncApiOptions>?setupAction = null)
        {
            var options = new AsyncApiOptions();

            setupAction?.Invoke(options);
            var wrappedOptions = Options.Create(options);

            var schemaGenerator   = new SchemaGenerator(wrappedOptions);
            var documentGenerator = new DocumentGenerator(Options.Create(options), schemaGenerator);

            return(new AsyncApiDocumentProvider(Options.Create(options), documentGenerator));
        }
コード例 #15
0
        public AsyncApiDocument GetDocument(AsyncApiOptions options, AsyncApiDocument prototype)
        {
            if (options == null)
            {
                throw new ArgumentNullException(nameof(options));
            }
            var asyncApiTypes = GetAsyncApiTypes(options, prototype);

            var document = _documentGenerator.GenerateDocument(asyncApiTypes, options, prototype, _serviceProvider);

            return(document);
        }
コード例 #16
0
        public void DocumentFilterIsAppliedToAsyncApiDocument()
        {
            // Arrange
            var options = new AsyncApiOptions();
            var documentGenerator = new DocumentGenerator();

            // Act
            options.AddDocumentFilter<ExampleDocumentFilter>();
            var document = documentGenerator.GenerateDocument(new[] { GetType().GetTypeInfo() }, options, options.AsyncApi, ActivatorServiceProvider.Instance);

            // Assert
            document.ShouldNotBeNull();
            document.Channels.Count.ShouldBe(1);
            document.Channels.ShouldContainKey("foo");
        }
コード例 #17
0
        public static bool IsEnum(this Type type, AsyncApiOptions options, out EnumMembers members)
        {
            if (type.IsEnum)
            {
                members = type.GetEnumMembers(options);
                return(true);
            }

            if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable <>))
            {
                var typeArgument = type.GetGenericArguments().Single();
                return(typeArgument.IsEnum(options, out members));
            }

            members = null;
            return(false);
        }
コード例 #18
0
        public AsyncApiUiMiddleware(RequestDelegate next, IOptions <AsyncApiOptions> options, IWebHostEnvironment env, ILoggerFactory loggerFactory)
#endif
        {
            _options = options.Value;
            var fileProvider      = new EmbeddedFileProvider(GetType().Assembly, GetType().Namespace);
            var staticFileOptions = new StaticFileOptions
            {
                RequestPath  = UiBaseRoute,
                FileProvider = fileProvider,
            };

            _staticFiles      = new StaticFileMiddleware(next, env, Options.Create(staticFileOptions), loggerFactory);
            _namedStaticFiles = new Dictionary <string, StaticFileMiddleware>();

            foreach (var namedApi in _options.NamedApis)
            {
                var namedStaticFileOptions = new StaticFileOptions
                {
                    RequestPath  = UiBaseRoute.Replace("{document}", namedApi.Key),
                    FileProvider = fileProvider,
                };
                _namedStaticFiles.Add(namedApi.Key, new StaticFileMiddleware(next, env, Options.Create(namedStaticFileOptions), loggerFactory));
            }
        }
コード例 #19
0
        /// <summary>
        /// Generate the an operation of an AsyncApi Channel for the given method.
        /// </summary>
        private static Operation GenerateOperationFromMethod(MethodInfo method, AsyncApiSchemaResolver schemaResolver, OperationType operationType, AsyncApiOptions options, JsonSchemaGenerator jsonSchemaGenerator, IServiceProvider serviceProvider)
        {
            var operationAttribute = GetOperationAttribute(method, operationType);

            if (operationAttribute == null)
            {
                return(null);
            }

            IEnumerable <MessageAttribute> messageAttributes = method.GetCustomAttributes <MessageAttribute>();
            var message = messageAttributes.Any()
                ? GenerateMessageFromAttributes(messageAttributes, schemaResolver, jsonSchemaGenerator)
                : GenerateMessageFromType(operationAttribute.MessagePayloadType, schemaResolver, jsonSchemaGenerator);

            var operation = new Operation
            {
                OperationId = operationAttribute.OperationId ?? method.Name,
                Summary     = operationAttribute.Summary ?? method.GetXmlDocsSummary(),
                Description = operationAttribute.Description ?? (method.GetXmlDocsRemarks() != "" ? method.GetXmlDocsRemarks() : null),
                Message     = message,
                Bindings    = operationAttribute.BindingsRef != null ? new OperationBindingsReference(operationAttribute.BindingsRef) : null,
            };

            var filterContext = new OperationFilterContext(method, schemaResolver, jsonSchemaGenerator, operationAttribute);

            foreach (var filterType in options.OperationFilters)
            {
                var filter = (IOperationFilter)serviceProvider.GetRequiredService(filterType);
                filter?.Apply(operation, filterContext);
            }

            return(operation);
        }
コード例 #20
0
        /// <summary>
        /// Generate the Channels section of the AsyncApi schema from the
        /// <see cref="ChannelAttribute"/> on methods.
        /// </summary>
        private static IDictionary <string, ChannelItem> GenerateChannelsFromMethods(IEnumerable <TypeInfo> asyncApiTypes, AsyncApiSchemaResolver schemaResolver, AsyncApiOptions options, JsonSchemaGenerator jsonSchemaGenerator, IServiceProvider serviceProvider)
        {
            var channels = new Dictionary <string, ChannelItem>();

            var methodsWithChannelAttribute = asyncApiTypes
                                              .SelectMany(type => type.DeclaredMethods)
                                              .Select(method => new
            {
                Channel = method.GetCustomAttribute <ChannelAttribute>(),
                Method  = method,
            })
                                              .Where(mc => mc.Channel != null);

            foreach (var mc in methodsWithChannelAttribute)
            {
                var channelItem = new ChannelItem
                {
                    Description = mc.Channel.Description,
                    Parameters  = GetChannelParametersFromAttributes(mc.Method, schemaResolver, jsonSchemaGenerator),
                    Publish     = GenerateOperationFromMethod(mc.Method, schemaResolver, OperationType.Publish, options, jsonSchemaGenerator, serviceProvider),
                    Subscribe   = GenerateOperationFromMethod(mc.Method, schemaResolver, OperationType.Subscribe, options, jsonSchemaGenerator, serviceProvider),
                    Bindings    = mc.Channel.BindingsRef != null ? new ChannelBindingsReference(mc.Channel.BindingsRef) : null,
                    Servers     = mc.Channel.Servers?.ToList(),
                };
                channels.Add(mc.Channel.Name, channelItem);

                var context = new ChannelItemFilterContext(mc.Method, schemaResolver, jsonSchemaGenerator, mc.Channel);
                foreach (var filterType in options.ChannelItemFilters)
                {
                    var filter = (IChannelItemFilter)serviceProvider.GetRequiredService(filterType);
                    filter.Apply(channelItem, context);
                }
            }

            return(channels);
        }
コード例 #21
0
ファイル: SerializerTests.cs プロジェクト: tehmantra/saunter
 public SerializerTests()
 {
     _options           = new AsyncApiOptions();
     _documentGenerator = new DocumentGenerator();
 }
コード例 #22
0
 public AsyncApiDocumentProvider(IOptions <AsyncApiOptions> options, IDocumentGenerator documentGenerator)
 {
     _documentGenerator = documentGenerator;
     _options           = options?.Value ?? throw new ArgumentNullException(nameof(options));
 }
コード例 #23
0
 public string Serialize(AsyncApiDocument document, AsyncApiOptions options)
 {
     return JsonConvert.SerializeObject(document, options.JsonSchemaGeneratorSettings.ActualSerializerSettings);
 }
コード例 #24
0
 public SchemaGenerator(IOptions <AsyncApiOptions> options)
 {
     _options = options.Value ?? throw new ArgumentNullException(nameof(options));
 }
コード例 #25
0
 public DocumentGenerator(IOptions <AsyncApiOptions> options, ISchemaGenerator schemaGenerator)
 {
     _schemaGenerator = schemaGenerator;
     _options         = options?.Value ?? throw new ArgumentNullException(nameof(options));
 }
コード例 #26
0
        /// <summary>
        /// Generate the Channels section of an AsyncApi schema.
        /// </summary>
        private static IDictionary <string, ChannelItem> GenerateChannels(TypeInfo[] asyncApiTypes, AsyncApiSchemaResolver schemaResolver, AsyncApiOptions options, JsonSchemaGenerator jsonSchemaGenerator, IServiceProvider serviceProvider)
        {
            var channels = new Dictionary <string, ChannelItem>();

            channels.AddRange(GenerateChannelsFromMethods(asyncApiTypes, schemaResolver, options, jsonSchemaGenerator, serviceProvider));
            channels.AddRange(GenerateChannelsFromClasses(asyncApiTypes, schemaResolver, options, jsonSchemaGenerator, serviceProvider));
            return(channels);
        }
コード例 #27
0
        public void IsEnum_False_WhenTypeIsNotEnum(Type type)
        {
            var options = new AsyncApiOptions();

            type.IsEnum(options, out _).ShouldBeFalse();
        }
コード例 #28
0
        /// <summary>
        /// Generate the Channels section of the AsyncApi schema from the
        /// <see cref="ChannelAttribute"/> on classes.
        /// </summary>
        private static IDictionary <string, ChannelItem> GenerateChannelsFromClasses(IEnumerable <TypeInfo> asyncApiTypes, AsyncApiSchemaResolver schemaResolver, AsyncApiOptions options, JsonSchemaGenerator jsonSchemaGenerator, IServiceProvider serviceProvider)
        {
            var channels = new Dictionary <string, ChannelItem>();

            var classesWithChannelAttribute = asyncApiTypes
                                              .Select(type => new
            {
                Channel = type.GetCustomAttribute <ChannelAttribute>(),
                Type    = type,
            })
                                              .Where(cc => cc.Channel != null);

            foreach (var cc in classesWithChannelAttribute)
            {
                var channelItem = new ChannelItem
                {
                    Description = cc.Channel.Description,
                    Parameters  = GetChannelParametersFromAttributes(cc.Type, schemaResolver, jsonSchemaGenerator),
                    Publish     = GenerateOperationFromClass(cc.Type, schemaResolver, OperationType.Publish, jsonSchemaGenerator),
                    Subscribe   = GenerateOperationFromClass(cc.Type, schemaResolver, OperationType.Subscribe, jsonSchemaGenerator),
                    Bindings    = cc.Channel.BindingsRef != null ? new ChannelBindingsReference(cc.Channel.BindingsRef) : null,
                    Servers     = cc.Channel.Servers?.ToList(),
                };

                channels.AddOrAppend(cc.Channel.Name, channelItem);

                var context = new ChannelItemFilterContext(cc.Type, schemaResolver, jsonSchemaGenerator, cc.Channel);
                foreach (var filterType in options.ChannelItemFilters)
                {
                    var filter = (IChannelItemFilter)serviceProvider.GetRequiredService(filterType);
                    filter.Apply(channelItem, context);
                }
            }

            return(channels);
        }
コード例 #29
0
        public AsyncApiSchema.v2.AsyncApiDocument GenerateDocument(TypeInfo[] asyncApiTypes, AsyncApiOptions options, AsyncApiDocument prototype, IServiceProvider serviceProvider)
        {
            var asyncApiSchema = prototype.Clone();

            var schemaResolver = new AsyncApiSchemaResolver(asyncApiSchema, options.JsonSchemaGeneratorSettings);

            var generator = new JsonSchemaGenerator(options.JsonSchemaGeneratorSettings);

            asyncApiSchema.Channels = GenerateChannels(asyncApiTypes, schemaResolver, options, generator, serviceProvider);

            var filterContext = new DocumentFilterContext(asyncApiTypes, schemaResolver, generator);

            foreach (var filterType in options.DocumentFilters)
            {
                var filter = (IDocumentFilter)serviceProvider.GetRequiredService(filterType);
                filter?.Apply(asyncApiSchema, filterContext);
            }

            return(asyncApiSchema);
        }