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"); }
public SchemaGenerationTests() { _schemaRepository = new SchemaRepository(); var options = new AsyncApiOptions(); _schemaGenerator = new SchemaGenerator(Options.Create(options)); }
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); }
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"); }
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"); }
private static IEnumerable <string> GetEnumMemberNames(this Type type, AsyncApiOptions options) { foreach (Enum val in type.GetEnumValues()) { yield return(options.EnumMemberNameSelector(type, val)); } }
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"); }
public void RouteTemplate_WhenNotSet_ReturnsDefaultValue() { const string defaultRouteTemplate = "async-api/async-api.{json|yaml}"; var target = new AsyncApiOptions(); Assert.AreEqual(defaultRouteTemplate, target.RouteTemplate); }
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); }
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); }
/// <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); }
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())); }
public void RouteTemplate_WhenSet_ReturnsValue() { const string valueRouteTemplate = "some-route"; var target = new AsyncApiOptions { RouteTemplate = valueRouteTemplate }; Assert.AreEqual(valueRouteTemplate, target.RouteTemplate); }
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)); }
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); }
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"); }
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); }
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)); } }
/// <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); }
/// <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); }
public SerializerTests() { _options = new AsyncApiOptions(); _documentGenerator = new DocumentGenerator(); }
public AsyncApiDocumentProvider(IOptions <AsyncApiOptions> options, IDocumentGenerator documentGenerator) { _documentGenerator = documentGenerator; _options = options?.Value ?? throw new ArgumentNullException(nameof(options)); }
public string Serialize(AsyncApiDocument document, AsyncApiOptions options) { return JsonConvert.SerializeObject(document, options.JsonSchemaGeneratorSettings.ActualSerializerSettings); }
public SchemaGenerator(IOptions <AsyncApiOptions> options) { _options = options.Value ?? throw new ArgumentNullException(nameof(options)); }
public DocumentGenerator(IOptions <AsyncApiOptions> options, ISchemaGenerator schemaGenerator) { _schemaGenerator = schemaGenerator; _options = options?.Value ?? throw new ArgumentNullException(nameof(options)); }
/// <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); }
public void IsEnum_False_WhenTypeIsNotEnum(Type type) { var options = new AsyncApiOptions(); type.IsEnum(options, out _).ShouldBeFalse(); }
/// <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); }
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); }