public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context) { if (swaggerDoc == null) { throw new ArgumentNullException(nameof(swaggerDoc)); } var replacements = new OpenApiPaths(); foreach (var(key, value) in swaggerDoc.Paths) { replacements.Add(key.Replace("{version}", swaggerDoc.Info.Version, StringComparison.InvariantCulture), value); } swaggerDoc.Paths = replacements; }
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IHostEnvironment env) { if (env.IsDevelopment()) { //app.UseMiddleware<StackifyMiddleware.RequestTracerMiddleware>(); app.UseDeveloperExceptionPage(); } else { // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. app.UseHsts(); } app.UseForwardedHeaders(new ForwardedHeadersOptions { ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto }); app.UseRouting(); app.UseCors("AnyOrigin"); app.UseAuthentication(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); app.UseSwagger(c => { string basePath = System.Environment.GetEnvironmentVariable("ASPNETCORE_APPL_PATH") ?? "/"; c.PreSerializeFilters.Add((swaggerDoc, httpReq) => { var paths = new OpenApiPaths(); foreach (var path in swaggerDoc.Paths) { paths.Add(path.Key.Replace(basePath, "/"), path.Value); } swaggerDoc.Paths = paths; }); }); app.UseSwaggerUI(c => { c.SwaggerEndpoint("v1/swagger.json", "post API V1"); }); }
private static void FilterOnlyODataControllers(OpenApiDocument swaggerDoc, HttpRequest req) { // Filter Paths var apiPaths = swaggerDoc.Paths.Where(p => p.Key.StartsWith("/odata/")); var paths = new OpenApiPaths(); foreach (var path in apiPaths) { paths.Add(path.Key, path.Value); } swaggerDoc.Paths = paths; // Filter XmlComments var allTags = swaggerDoc.Tags; var tags = allTags.Where(tag => tag.Reference.ExternalResource == "odata").ToList(); swaggerDoc.Tags = tags; }
private OpenApiPaths GeneratePaths(IReadOnlyList <ServiceEntry> entries, SchemaRepository schemaRepository) { var entriesByPath = entries.OrderBy(_options.SortKeySelector) .GroupBy(p => p.Router.RoutePath); var paths = new OpenApiPaths(); foreach (var group in entriesByPath) { paths.Add($"/{group.Key}", new OpenApiPathItem { Operations = GenerateOperations(group, schemaRepository) }); } return(paths); }
/// <summary> /// Visits <see cref="OpenApiPaths"/> and child objects /// </summary> internal void Walk(OpenApiPaths paths) { if (paths == null) { return; } _visitor.Visit(paths); // Visit Paths if (paths != null) { foreach (var pathItem in paths) { Walk(pathItem.Key, () => Walk(pathItem.Value));// JSON Pointer uses ~1 as an escape character for / } } }
private static OpenApiPaths BuildPaths(IEnumerable <RestEndpoint> restEndpoints) { var dictionary = restEndpoints .ToDictionary(re => re.Path, re => new OpenApiPathItem() { Parameters = re.InputParameters .Select(ip => new OpenApiParameter() { Name = ip.Name, In = ip.ParameterLocation, Required = true, Schema = new OpenApiSchema() { Type = "string", }, Description = ip.Description, }).ToList(), Operations = re.InputOperations .ToDictionary(io => io.OperationType, io => new OpenApiOperation() { Description = io.Description, Responses = io.ResponseValues .ToDictionary(rv => rv.Name, rv => new OpenApiResponse() { Reference = new OpenApiReference() { Id = rv.Id, Type = ReferenceType.Response, }, }) as OpenApiResponses, }), }); var openApiPaths = new OpenApiPaths(); foreach (var kvp in dictionary) { openApiPaths.Add(kvp.Key, kvp.Value); } return(openApiPaths); }
/// <summary> /// Parses the parameters in the URL to populate the in attribute of the param tags as path or query /// if not explicitly documented. /// </summary> /// <param name="paths">The paths to be updated.</param> /// <param name="element">The xml element representing an operation in the annotation xml.</param> /// <param name="settings">The operation filter settings.</param> public void Apply(OpenApiPaths paths, XElement element, PreProcessingOperationFilterSettings settings) { var paramElementsWithoutIn = element.Elements().Where( p => p.Name == KnownXmlStrings.Param && p.Attribute(KnownXmlStrings.In)?.Value == null) .ToList(); var url = element.Elements() .FirstOrDefault(p => p.Name == KnownXmlStrings.Url) ?.Value; if (!string.IsNullOrWhiteSpace(url)) { foreach (var paramElement in paramElementsWithoutIn) { var paramName = paramElement.Attribute(KnownXmlStrings.Name)?.Value; if (url.Contains( $"/{{{paramName}}}", StringComparison.InvariantCultureIgnoreCase) && url.Contains( $"={{{paramName}}}", StringComparison.InvariantCultureIgnoreCase)) { // The parameter is in both path and query. We cannot determine what to put for "in" attribute. throw new ConflictingPathAndQueryParametersException(paramName, url); } if (url.Contains( $"/{{{paramName}}}", StringComparison.InvariantCultureIgnoreCase)) { paramElement.Add(new XAttribute(KnownXmlStrings.In, KnownXmlStrings.Path)); } else if (url.Contains( $"={{{paramName}}}", StringComparison.InvariantCultureIgnoreCase)) { paramElement.Add(new XAttribute(KnownXmlStrings.In, KnownXmlStrings.Query)); } } } }
/// <summary> /// /// </summary> /// <param name="app"></param> /// <param name="configuration"></param> /// <returns></returns> public static IApplicationBuilder UseKaneko(this IApplicationBuilder app, IConfiguration configuration) { string serviceName = configuration["ServiceName"]; if (bool.Parse(configuration["Consul:Enable"])) { app.UseConsul(); } app.UseCors(serviceName); app.UseSwagger(c => { //加上服务名,支持直接在ocelot进行api测试 string basepath = ""; if (!string.IsNullOrEmpty(serviceName)) { basepath = $"/{serviceName}"; } c.PreSerializeFilters.Add((swaggerDoc, httpReq) => { OpenApiPaths paths = new OpenApiPaths(); foreach (var path in swaggerDoc.Paths) { paths.Add(basepath + path.Key, path.Value); } swaggerDoc.Paths = paths; }); }); app.UseSwaggerUI(options => { options.SwaggerEndpoint("/swagger/v1/swagger.json", serviceName); options.RoutePrefix = string.Empty; }); app.UseRouting(); app.UseEndpoints(endpoints => { endpoints.MapDefaultControllerRoute(); }); return(app); }
//public CompilerResults CompileThenSave(string fileName)//not working in .net core //{ // using CodeDomProvider provider = CodeDomProvider.CreateProvider("CSharp"); // CodeGeneratorOptions options = new CodeGeneratorOptions() { BracingStyle = "C", IndentString = "\t" }; // var s = WriteToText(); // var results = provider.CompileAssemblyFromSource( //https://docs.microsoft.com/en-us/dotnet/core/compatibility/unsupported-apis // new CompilerParameters(new string[] { "System.Net.Http", "Newtonsoft.Json" }) // { // GenerateInMemory = true, // }, s // ); // File.WriteAllText(fileName, s); //save the file anyway // return results; //} string[] GetContainerClassNames(OpenApiPaths paths) { if (settings.ContainerNameStrategy == ContainerNameStrategy.None) { return(new string[] { settings.ContainerClassName }); } List <string> names = new List <string>(); foreach (KeyValuePair <string, OpenApiPathItem> p in paths) { foreach (KeyValuePair <OperationType, OpenApiOperation> op in p.Value.Operations) { string name = nameComposer.GetContainerName(op.Value, p.Key); names.Add(name); } } return(names.Distinct().ToArray()); }
private OpenApiPaths GeneratePaths(IEnumerable <ApiDescription> apiDescriptions, SchemaRepository schemaRepository) { var apiDescriptionsByPath = apiDescriptions .OrderBy(_options.SortKeySelector) .GroupBy(apiDesc => apiDesc.RelativePathSansQueryString()); var paths = new OpenApiPaths(); foreach (var group in apiDescriptionsByPath) { paths.Add($"/{group.Key}", new OpenApiPathItem { Operations = GenerateOperations(group, schemaRepository) }); } ; return(paths); }
/// <inheritdoc/> public OpenApiDocument GenerateFor(IDebuggingHandler handler) { var repository = new SchemaRepository(); var paths = new OpenApiPaths(); GeneratePaths(paths, handler, repository); return(new OpenApiDocument { Info = new OpenApiInfo { Title = handler.Title, }, Paths = paths, Components = new OpenApiComponents { Schemas = repository.Schemas, }, }); }
void GeneratePaths(OpenApiPaths paths, IDebuggingHandler handler, SchemaRepository repository) { foreach ((var path, var artifact) in handler.Artifacts) { var item = new OpenApiPathItem(); AddGetOperation(handler, item, GenerateOperation(handler, artifact, repository)); AddPostOperation(handler, item, GenerateOperation(handler, artifact, repository)); var tag = path.ToString().Contains('/', StringComparison.InvariantCultureIgnoreCase) ? path.ToString().Split('/')[1] : path.ToString(); foreach ((_, var operation) in item.Operations) { operation.Tags = new[] { new OpenApiTag { Name = tag } }; } paths.Add(path, item); } }
/// <summary> /// Fetches the URL value and creates multiple operations based on optional parameters. /// </summary> /// <param name="paths">The paths to be updated.</param> /// <param name="element">The xml element representing an operation in the annotation xml.</param> /// <param name="settings">The operation filter settings.</param> public void Apply(OpenApiPaths paths, XElement element, PreProcessingOperationFilterSettings settings) { var paramElements = element.Elements() .Where( p => p.Name == KnownXmlStrings.Param) .ToList(); // We need both the full URL and the absolute paths for processing. // Full URL contains all path and query parameters. // Absolute path is needed to get OperationId parsed out correctly. var fullUrl = element.Elements() .FirstOrDefault(p => p.Name == KnownXmlStrings.Url) ?.Value; var absolutePath = fullUrl.UrlStringToAbsolutePath(); var operationMethod = (OperationType)Enum.Parse( typeof(OperationType), element.Elements().FirstOrDefault(p => p.Name == KnownXmlStrings.Verb)?.Value, ignoreCase: true); var allGeneratedPathStrings = GeneratePossiblePaths( absolutePath, paramElements.Where( p => p.Attribute(KnownXmlStrings.In)?.Value == KnownXmlStrings.Path) .ToList()); foreach (var pathString in allGeneratedPathStrings) { if (!paths.ContainsKey(pathString)) { paths[pathString] = new OpenApiPathItem(); } paths[pathString].Operations[operationMethod] = new OpenApiOperation { OperationId = OperationHandler.GetOperationId(pathString, operationMethod) }; } }
public static SwaggerOptions Rebase(this SwaggerOptions options, Func <PathString, PathString> rebase) { options .PreSerializeFilters .Add ( (swagger, httpReq) => { var rebasedPaths = new OpenApiPaths(); foreach (var path in swagger.Paths) { rebasedPaths.Add(Uri.UnescapeDataString(rebase.Invoke(path.Key)), path.Value); } swagger.Paths = rebasedPaths; } ); return(options); }
private OpenApiPaths GetOpenApiPaths(RpcRouteMetaData metaData, SchemaRepository schemaRepository) { OpenApiPaths paths = new OpenApiPaths(); List <UniqueMethod> uniqueMethods = this.GetUniqueKeyMethodPairs(metaData); foreach (UniqueMethod method in uniqueMethods) { string operationKey = method.UniqueUrl.Replace("/", "_").Replace("#", "|"); OpenApiOperation operation = this.GetOpenApiOperation(operationKey, method.Info, schemaRepository); var pathItem = new OpenApiPathItem() { Operations = new Dictionary <OperationType, OpenApiOperation>() { [OperationType.Post] = operation } }; paths.Add(method.UniqueUrl, pathItem); } return(paths); }
public void TestApply() { var filterRoutesDocumentFilter = new FilterRoutesDocumentFilter(); var schemaGeneratorMock = new Mock <ISchemaGenerator>(); var paths = new OpenApiPaths { { VersionPrefix + "someVersionedEndpoint", new OpenApiPathItem() }, { VersionPrefix + "someOtherVersionedEndpoint", new OpenApiPathItem() }, { "EndpointWithoutVersion", new OpenApiPathItem() } }; var swaggerDoc = new OpenApiDocument { Paths = paths }; var context = new DocumentFilterContext(new[] { new ApiDescription() }, schemaGeneratorMock.Object, new SchemaRepository()); filterRoutesDocumentFilter.Apply(swaggerDoc, context); swaggerDoc.Paths.Keys.Should().NotContain(key => !key.StartsWith(VersionPrefix)); }
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IHostingEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); //过滤器 app.UseSwagger(c => { c.PreSerializeFilters.Add((swaggerDoc, httpReq) => { OpenApiPaths paths = new OpenApiPaths(); foreach (var path in swaggerDoc.Paths) { if (path.Key.StartsWith("/api/"))//过滤Path { paths.Add(path.Key, path.Value); } } swaggerDoc.Paths = paths; swaggerDoc.Servers = new List <OpenApiServer> { new OpenApiServer { Url = $"{httpReq.Scheme}://{httpReq.Host.Value}" } }; }); }); app.UseSwaggerUI(options => { options.SwaggerEndpoint("/swagger/Examination/swagger.json", "Examination");//Swagger文档路径 options.SwaggerEndpoint("/swagger/Business/swagger.json", "Business"); options.SwaggerEndpoint("/swagger/Authority/swagger.json", "Authority"); options.SwaggerEndpoint("/swagger/Social/swagger.json", "Social"); options.RoutePrefix = "";//设置为首页访问 }); } app.UseMvc(); }
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseHttpsRedirection(); app.UseRouting(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); app.UseSwagger(c => { c.PreSerializeFilters.Add((swaggerDoc, httpReq) => { var paths = new OpenApiPaths(); foreach (var path in swaggerDoc.Paths) { paths.Add(BasePath + path.Key, path.Value); } swaggerDoc.Paths = paths; var servers = new OpenApiServer { Url = httpReq.Host + BasePath, }; swaggerDoc.Servers.Add(servers); }); }); app.UseSwaggerUI(c => { c.SwaggerEndpoint("/swagger/v1/swagger.json", "Swashbuckle Test API V1"); }); }
private static List <LogKeyValueItem> ValidatePathsAndOperations( ApiOptionsValidation validationOptions, OpenApiPaths paths) { var logItems = new List <LogKeyValueItem>(); var logCategory = validationOptions.StrictMode ? LogCategoryType.Error : LogCategoryType.Warning; foreach (var path in paths) { if (!path.Key.IsStringFormatParametersBalanced(false)) { logItems.Add(LogItemHelper.Create(logCategory, ValidationRuleNameConstants.Path01, $"Path parameters are not well-formatted for '{path.Key}'.")); } var globalPathParameterNames = path.Value.Parameters .Where(x => x.In == ParameterLocation.Path) .Select(x => x.Name) .ToList(); if (globalPathParameterNames.Any()) { logItems.AddRange(ValidatePathsAndOperationsHelper.ValidateGlobalParameters(validationOptions, globalPathParameterNames, path)); } else { logItems.AddRange(ValidatePathsAndOperationsHelper.ValidateMissingOperationParameters(validationOptions, path)); logItems.AddRange(ValidatePathsAndOperationsHelper.ValidateOperationsWithParametersNotPresentInPath(validationOptions, path)); } logItems.AddRange(ValidatePathsAndOperationsHelper.ValidateGetOperations(validationOptions, path)); } return(logItems); }
public override void Visit(OpenApiPaths item) => Validate(item);
/// <summary> /// Converts the alternative param tags (queryParam, pathParam, header) to standard param tags. /// </summary> /// <param name="paths">The paths to be updated.</param> /// <param name="element">The xml element representing an operation in the annotation xml.</param> /// <param name="settings">The operation filter settings.</param> public void Apply(OpenApiPaths paths, XElement element, PreProcessingOperationFilterSettings settings) { var pathParamElements = element.Elements() .Where(p => p.Name == KnownXmlStrings.PathParam) .ToList(); var queryParamElements = element.Elements() .Where(p => p.Name == KnownXmlStrings.QueryParam) .ToList(); var headerParamElements = element.Elements() .Where(p => p.Name == KnownXmlStrings.Header) .ToList(); var requestTypeElements = element.Elements() .Where(p => p.Name == KnownXmlStrings.RequestType) .ToList(); var paramElements = element.Elements().Where(i => i.Name == KnownXmlStrings.Param); if (pathParamElements.Any()) { foreach (var pathParamElement in pathParamElements) { var conflictingPathParam = paramElements.Where( i => i.Attribute("name")?.Value == pathParamElement.Attribute("name")?.Value); // Remove param tags that have same name as pathParam tags // e.g. if service is documented like below, it will remove the param tag // // <param name="samplePathParam">Sample path param</param> // <pathParam name="samplePathParam" in="path">Sample path param</pathParam> conflictingPathParam?.Remove(); pathParamElement.Name = KnownXmlStrings.Param; pathParamElement.Add(new XAttribute(KnownXmlStrings.In, KnownXmlStrings.Path)); } } if (queryParamElements.Any()) { foreach (var queryParamElement in queryParamElements) { var conflictingQueryParam = paramElements.Where( i => i.Attribute("name")?.Value == queryParamElement.Attribute("name")?.Value); // Remove param tags that have same name as queryParam tags // e.g. if service is documented like below, it will remove the param tag // // <param name="sampleQueryParam">Sample query param</param> // <queryParam name="sampleQueryParam" in="path">Sample query param</queryParam> conflictingQueryParam?.Remove(); queryParamElement.Name = KnownXmlStrings.Param; queryParamElement.Add(new XAttribute(KnownXmlStrings.In, KnownXmlStrings.Query)); } } if (requestTypeElements.Any()) { var paramTagToRemove = element.Elements() .Where(i => i.Name == KnownXmlStrings.Param && string.IsNullOrWhiteSpace(i.Attribute("in")?.Value)); // If there are still conflicting param tags remaining, then it's safe to assume that these are neither // path nor query params and could be documented request params which is not intended to be used with // C# document generator so remove the tags. paramTagToRemove?.Remove(); foreach (var requestTypeElement in requestTypeElements) { requestTypeElement.Name = KnownXmlStrings.Param; requestTypeElement.Add(new XAttribute(KnownXmlStrings.In, KnownXmlStrings.Body)); } } foreach (var headerParamElement in headerParamElements) { headerParamElement.Name = KnownXmlStrings.Param; headerParamElement.Add(new XAttribute(KnownXmlStrings.In, KnownXmlStrings.Header)); } }
/// <summary> /// Use swagger in application /// </summary> /// <param name="app"></param> public static void UseSwagger(this IApplicationBuilder app) { var config = app.ApplicationServices.GetRequiredService <IOpenApiConfig>(); var auth = app.ApplicationServices.GetService <IServerAuthConfig>(); var server = app.ApplicationServices.GetRequiredService <IServer>(); var addresses = app.ServerFeatures.Get <IServerAddressesFeature>()?.Addresses .Select(a => new Uri(a.Replace("://*", "://localhost"))) .ToList() ?? new List <Uri>(); // Enable swagger and swagger ui app.UseSwagger(options => { options.PreSerializeFilters.Add((doc, request) => { doc.Servers = new List <OpenApiServer>(); foreach (var scheme in addresses .Select(a => a.Scheme) .Append("https") .Append(request.Scheme) .Distinct()) { var url = $"{scheme}://{request.Host.Value}"; // If config.OpenApiServerHost is set, we will use that instead of request.Host.Value if (!string.IsNullOrEmpty(config.OpenApiServerHost)) { url = $"{scheme}://{config.OpenApiServerHost}"; } doc.Servers.Add(new OpenApiServer { Description = $"{scheme} endpoint.", Url = url }); } // If request.PathBase exists, then we will prepend it to doc.Paths. if (request.PathBase.HasValue) { var pathBase = request.PathBase.Value; var prefixedPaths = new OpenApiPaths(); foreach (var path in doc.Paths) { prefixedPaths.Add(pathBase + path.Key, path.Value); } doc.Paths = prefixedPaths; } }); options.SerializeAsV2 = true; options.RouteTemplate = "swagger/{documentName}/openapi.json"; }); if (!config.UIEnabled) { return; } var api = app.ApplicationServices.GetRequiredService <IActionDescriptorCollectionProvider>(); var infos = api.GetOpenApiInfos(null, null); // Where to host the ui app.UseSwaggerUI(options => { foreach (var info in infos) { if (config.WithAuth) { options.OAuthAppName(info.Title); options.OAuthClientId(config.OpenApiAppId); if (!string.IsNullOrEmpty(config.OpenApiAppSecret)) { options.OAuthClientSecret(config.OpenApiAppSecret); } var resource = auth?.JwtBearerProviders?.FirstOrDefault(); if (!string.IsNullOrEmpty(resource?.Audience)) { options.OAuthAdditionalQueryStringParams( new Dictionary <string, string> { ["resource"] = resource.Audience }); } } options.SwaggerEndpoint($"{info.Version}/openapi.json", info.Version); } }); }
/// <summary> /// Visits <see cref="OpenApiPaths"/> /// </summary> public virtual void Visit(OpenApiPaths paths) { }
/// <inheritdoc /> public IDocument Build(Assembly assembly) { if (this._strategy.IsNullOrDefault()) { this._strategy = new DefaultNamingStrategy(); } var paths = new OpenApiPaths(); var methods = this._helper.GetHttpTriggerMethods(assembly); foreach (var method in methods) { var trigger = this._helper.GetHttpTriggerAttribute(method); if (trigger.IsNullOrDefault()) { continue; } var function = this._helper.GetFunctionNameAttribute(method); if (function.IsNullOrDefault()) { continue; } var path = this._helper.GetHttpEndpoint(function, trigger); if (path.IsNullOrWhiteSpace()) { continue; } var verb = this._helper.GetHttpVerb(trigger); var item = this._helper.GetOpenApiPath(path, paths); var operations = item.Operations; var operation = this._helper.GetOpenApiOperation(method, function, verb); if (operation.IsNullOrDefault()) { continue; } operation.Security = this._helper.GetOpenApiSecurityRequirement(method, this._strategy); operation.Parameters = this._helper.GetOpenApiParameters(method, trigger, this._strategy, this._collection); operation.RequestBody = this._helper.GetOpenApiRequestBody(method, this._strategy, this._collection); operation.Responses = this._helper.GetOpenApiResponses(method, this._strategy, this._collection); operations[verb] = operation; item.Operations = operations; paths[path] = item; } this.OpenApiDocument.Paths = paths; this.OpenApiDocument.Components.Schemas = this._helper.GetOpenApiSchemas(methods, this._strategy, this._collection); this.OpenApiDocument.Components.SecuritySchemes = this._helper.GetOpenApiSecuritySchemes(methods, this._strategy); // this.OpenApiDocument.SecurityRequirements = this.OpenApiDocument // .Paths // .SelectMany(p => p.Value.Operations.SelectMany(q => q.Value.Security)) // .Where(p => !p.IsNullOrDefault()) // .Distinct(new OpenApiSecurityRequirementComparer()) // .ToList(); return(this); }
/// <inheritdoc /> public OpenApiPathItem GetOpenApiPath(string path, OpenApiPaths paths) { var item = paths.ContainsKey(path) ? paths[path] : new OpenApiPathItem(); return(item); }
public static void GenerateClientAPIs(Settings settings, OpenApiPaths paths, OpenApiComponents components, string outputBasePath) { string currentDir = System.IO.Directory.GetCurrentDirectory(); if (settings.ClientLibraryProjectFolderName != null) { string csharpClientProjectDir = System.IO.Path.IsPathRooted(settings.ClientLibraryProjectFolderName) ? settings.ClientLibraryProjectFolderName : System.IO.Path.Combine(outputBasePath, settings.ClientLibraryProjectFolderName); if (!System.IO.Directory.Exists(csharpClientProjectDir)) { if (settings.CreateFolder) { System.IO.Directory.CreateDirectory(csharpClientProjectDir); } else { string msg = $"{csharpClientProjectDir} not exist while current directory is {currentDir}"; throw new CodeGenException(msg); } } string path = System.IO.Path.Combine(csharpClientProjectDir, settings.ClientLibraryFileName); ControllersClientApiGen gen = new ControllersClientApiGen(settings); gen.CreateCodeDom(paths, components); gen.Save(path); } string CreateTsPath(string folder, string fileName) { if (folder != null) { string theFolder; try { theFolder = System.IO.Path.IsPathRooted(folder) ? folder : System.IO.Path.Combine(outputBasePath, folder); if (!System.IO.Directory.Exists(theFolder)) { if (settings.CreateFolder) { System.IO.Directory.CreateDirectory(theFolder); } else { string msg = $"{theFolder} not exist while current directory is {currentDir}"; throw new CodeGenException(msg); } } } catch (ArgumentException e) { Trace.TraceWarning(e.Message); string msg = $"Invalid TypeScriptFolder {folder} while current directory is {currentDir}"; throw new CodeGenException(msg); } if (!System.IO.Directory.Exists(theFolder)) { string msg = $"TypeScriptFolder {theFolder} not exist while current directory is {currentDir}"; throw new CodeGenException(msg); } return(System.IO.Path.Combine(theFolder, fileName)); } ; return(null); } if (settings.Plugins != null) { string exeDir = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location); foreach (JSPlugin plugin in settings.Plugins) { JSOutput jsOutput = new JSOutput { JSPath = CreateTsPath(plugin.TargetDir, plugin.TSFile), AsModule = plugin.AsModule, ContentType = plugin.ContentType, }; string assemblyFilePath = System.IO.Path.Combine(exeDir, plugin.AssemblyName + ".dll"); Ts.ControllersTsClientApiGenBase tsGen = PluginFactory.CreateImplementationsFromAssembly(assemblyFilePath, settings, jsOutput); if (tsGen != null) { Trace.TraceInformation($"Generate codes with {tsGen.ProductName} ......"); tsGen.CreateCodeDom(paths, components); tsGen.Save(); } else { Trace.TraceWarning($"Not done with plugin {plugin.AssemblyName}"); } } } }
/// <summary> /// Converts the alternative param tags (queryParam, pathParam, header) to standard param tags. /// </summary> /// <param name="paths">The paths to be updated.</param> /// <param name="element">The xml element representing an operation in the annotation xml.</param> /// <param name="settings">The operation filter settings.</param> /// <returns>The list of generation errors, if any produced when processing the filter.</returns> public IList <GenerationError> Apply( OpenApiPaths paths, XElement element, PreProcessingOperationFilterSettings settings) { var generationErrors = new List <GenerationError>(); try { var pathParamElements = element.Elements() .Where(p => p.Name == KnownXmlStrings.PathParam) .ToList(); var queryParamElements = element.Elements() .Where(p => p.Name == KnownXmlStrings.QueryParam) .ToList(); var headerParamElements = element.Elements() .Where(p => p.Name == KnownXmlStrings.Header) .ToList(); var requestTypeElements = element.Elements() .Where(p => p.Name == KnownXmlStrings.RequestType) .ToList(); var paramElements = element.Elements().Where(i => i.Name == KnownXmlStrings.Param); var paramElementsWithInAttributeNotSpecified = paramElements.Where(i => i.Attribute("in") == null); if (pathParamElements.Any()) { foreach (var pathParamElement in pathParamElements) { var conflictingPathParam = paramElements.Where( i => i.Attribute("name")?.Value == pathParamElement.Attribute("name")?.Value); // Remove param tags that have same name as pathParam tags // e.g. if service is documented like below, it will remove the param tag // // <param name="samplePathParam">Sample path param</param> // <pathParam name="samplePathParam" in="path">Sample path param</pathParam> conflictingPathParam?.Remove(); var nameAttribute = pathParamElement.Attribute(KnownXmlStrings.Name); var name = nameAttribute?.Value.Trim(); if (!string.IsNullOrWhiteSpace(name)) { nameAttribute.Value = name; } pathParamElement.Name = KnownXmlStrings.Param; pathParamElement.Add(new XAttribute(KnownXmlStrings.In, KnownXmlStrings.Path)); } } if (queryParamElements.Any()) { foreach (var queryParamElement in queryParamElements) { var conflictingQueryParam = paramElements.Where( i => i.Attribute("name")?.Value == queryParamElement.Attribute("name")?.Value); // Remove param tags that have same name as queryParam tags // e.g. if service is documented like below, it will remove the param tag // // <param name="sampleQueryParam">Sample query param</param> // <queryParam name="sampleQueryParam" in="path">Sample query param</queryParam> conflictingQueryParam?.Remove(); var nameAttribute = queryParamElement.Attribute(KnownXmlStrings.Name); var name = nameAttribute?.Value.Trim(); if (!string.IsNullOrWhiteSpace(name)) { nameAttribute.Value = name; } queryParamElement.Name = KnownXmlStrings.Param; queryParamElement.Add(new XAttribute(KnownXmlStrings.In, KnownXmlStrings.Query)); } } if (requestTypeElements.Any()) { var paramTagToRemove = element.Elements() .Where(i => i.Name == KnownXmlStrings.Param && string.IsNullOrWhiteSpace(i.Attribute("in")?.Value)); // If there are still conflicting param tags remaining, then it's safe to assume that these are neither // path nor query params and could be documented request params which is not intended to be used with // C# document generator so remove the tags. paramTagToRemove?.Remove(); foreach (var requestTypeElement in requestTypeElements) { requestTypeElement.Name = KnownXmlStrings.Param; requestTypeElement.Add(new XAttribute(KnownXmlStrings.In, KnownXmlStrings.Body)); } } foreach (var headerParamElement in headerParamElements) { var nameAttribute = headerParamElement.Attribute(KnownXmlStrings.Name); var name = nameAttribute?.Value.Trim(); if (!string.IsNullOrWhiteSpace(name)) { nameAttribute.Value = name; } headerParamElement.Name = KnownXmlStrings.Param; headerParamElement.Add(new XAttribute(KnownXmlStrings.In, KnownXmlStrings.Header)); } // If any of the alternative tags are present then remove any param tag element that have "in" attribute // not specified b/c assumption is made that those params are not supposed to be processed by // CSharp Annotation Document Generator. if (pathParamElements.Any() || queryParamElements.Any() || requestTypeElements.Any() || headerParamElements.Any()) { paramElementsWithInAttributeNotSpecified?.Remove(); } } catch (Exception ex) { generationErrors.Add( new GenerationError { Message = ex.Message, ExceptionType = ex.GetType().Name }); } return(generationErrors); }
public override void Visit(OpenApiPaths paths) { Locations.Add(this.PathString); }
public OpenApiPaths GeneratePaths() { OpenApiPaths paths = new OpenApiPaths(); foreach (Ac4yClass ac4yClass in Parameter.ClassList) { paths .Add( "/" + ac4yClass.Name + "/{id}", new OpenApiPathItem { Operations = new Dictionary <OperationType, OpenApiOperation> { [OperationType.Get] = new OpenApiOperation { Description = "Egy, az adott id-hez tartozó, " + ac4yClass.Name + " típusú rekord lekérdezése.", Parameters = new List <OpenApiParameter> { new OpenApiParameter { Name = "id", In = ParameterLocation.Path, Description = "A rekord is-ével lekérdezi a konkrét rekordot", Required = true, Schema = new OpenApiSchema { Type = "integer" } } }, Responses = new OpenApiResponses { ["200"] = new OpenApiResponse { Description = "A lekérdezés sikeres volt, a rekord adatait adja vissza", Content = { ["application/json"] = new OpenApiMediaType { Schema = new OpenApiSchema { Title = "Vendor", Reference = new OpenApiReference { Type = ReferenceType.Schema, Id = ac4yClass.Name } } } } }, ["400"] = new OpenApiResponse { Description = "A kérés hibára futott, a hibaüzenet bővebben tájékoztat", Content = { ["application/json"] = new OpenApiMediaType { Schema = new OpenApiSchema { Title = "Hiba üzenet", Properties = new Dictionary <string, OpenApiSchema> { ["Message"] = new OpenApiSchema { Type = "string", Description = "A hibáról informáló üzenet" } } } } } } } }, [OperationType.Patch] = new OpenApiOperation { Description = "Update-el 1 adott rekordot az id alapján", Parameters = new List <OpenApiParameter> { new OpenApiParameter { Name = "id", In = ParameterLocation.Path, Description = "A rekord id-hez tartozó rekordot fogja frissíteni", Required = true, Schema = new OpenApiSchema { Type = "integer" } } }, RequestBody = new OpenApiRequestBody { Required = true, Content = { ["application/json"] = new OpenApiMediaType { Example = GenerateExample(ac4yClass), Schema = new OpenApiSchema { Title = "Vendor", Reference = new OpenApiReference { Type = ReferenceType.Schema, Id = ac4yClass.Name + "WithoutID" } } } } }, Responses = new OpenApiResponses { ["200"] = new OpenApiResponse { Description = "Az adatok frissítése sikeres volt, a rekord a db-ben is frissült", }, ["400"] = new OpenApiResponse { Description = "A kérés hibára futott, a hibaüzenet bővebben tájékoztat", Content = { ["application/json"] = new OpenApiMediaType { Schema = new OpenApiSchema { Title = "Hiba üzenet", Properties = new Dictionary <string, OpenApiSchema> { ["Message"] = new OpenApiSchema { Type = "string", Description = "A hibáról informáló üzenet" } } } } } } } }, [OperationType.Delete] = new OpenApiOperation { Description = "Töröl 1, adott rekordot az id alapján és a rekordhoz tartozó összes kapcsolt rekordot " + "\nKapcsolt rekordok: " + GetConnectedPropertyNames(ac4yClass), Parameters = new List <OpenApiParameter> { new OpenApiParameter { Name = "id", In = ParameterLocation.Path, Description = "A rekord id-ével törli a konkrét rekordot és a hozzá kapcsolódókat is. " + "\nKapcsolt rekordok: " + GetConnectedPropertyNames(ac4yClass), Required = true, Schema = new OpenApiSchema { Type = "integer" } } }, Responses = new OpenApiResponses { ["200"] = new OpenApiResponse { Description = "A törlés sikeres volt, a rekord a db-ből is törlődött", }, ["400"] = new OpenApiResponse { Description = "A kérés hibára futott, a hibaüzenet bővebben tájékoztat", Content = { ["application/json"] = new OpenApiMediaType { Schema = new OpenApiSchema { Title = "Hiba üzenet", Properties = new Dictionary <string, OpenApiSchema> { ["Message"] = new OpenApiSchema { Type = "string", Description = "A hibáról informáló üzenet" } } } } } } } } } } ); paths.Add( "/" + ac4yClass.Name, new OpenApiPathItem { Operations = new Dictionary <OperationType, OpenApiOperation> { [OperationType.Get] = new OpenApiOperation { Description = ac4yClass.Name + "típusú rekordok lekérdezése", Responses = new OpenApiResponses { ["200"] = new OpenApiResponse { Description = "A lekérdezés sikeres volt, a rekordok listáját adja vissza", Content = { ["application/json"] = new OpenApiMediaType { Schema = new OpenApiSchema { Type = "array", Items = new OpenApiSchema { Reference = new OpenApiReference { Type = ReferenceType.Schema, Id = ac4yClass.Name } } } } } }, ["400"] = new OpenApiResponse { Description = "A kérés hibára futott, a hibaüzenet bővebben tájékoztat", Content = { ["application/json"] = new OpenApiMediaType { Schema = new OpenApiSchema { Title = "Hiba üzenet", Properties = new Dictionary <string, OpenApiSchema> { ["Message"] = new OpenApiSchema { Type = "string", Description = "A hibáról informáló üzenet" } } } } } } } }, [OperationType.Post] = new OpenApiOperation { Description = "Új rekord létrehozása", RequestBody = new OpenApiRequestBody { Required = true, Content = { ["application/json"] = new OpenApiMediaType { Example = GenerateExample(ac4yClass), Schema = new OpenApiSchema { Title = "Vendor", Reference = new OpenApiReference { Type = ReferenceType.Schema, Id = ac4yClass.Name + "WithoutID" } } } } }, Responses = new OpenApiResponses { ["200"] = new OpenApiResponse { Description = "A felvitel sikeres volt, a rekord a db-be is bekerült", }, ["400"] = new OpenApiResponse { Description = "A kérés hibára futott, a hibaüzenet bővebben tájékoztat", Content = { ["application/json"] = new OpenApiMediaType { Schema = new OpenApiSchema { Title = "Hiba üzenet", Properties = new Dictionary <string, OpenApiSchema> { ["Message"] = new OpenApiSchema { Type = "string", Description = "A hibáról informáló üzenet" } } } } } } } } } } ); } return(paths); }
/// <summary> /// Add operation and update the operation filter settings based on the given document variant info. /// </summary> private void AddOperation( IDictionary <DocumentVariantInfo, OpenApiDocument> specificationDocuments, IDictionary <DocumentVariantInfo, ReferenceRegistryManager> referenceRegistryManagerMap, IList <GenerationError> operationGenerationErrors, DocumentVariantInfo documentVariantInfo, XElement operationElement, XElement operationConfigElement, TypeFetcher typeFetcher) { var paths = new OpenApiPaths(); foreach (var preprocessingOperationFilter in _preProcessingOperationFilters) { try { preprocessingOperationFilter.Apply( paths, operationElement, new PreProcessingOperationFilterSettings()); } catch (Exception e) { operationGenerationErrors.Add( new GenerationError { ExceptionType = e.GetType().Name, Message = e.Message } ); } } if (!referenceRegistryManagerMap.ContainsKey(documentVariantInfo)) { referenceRegistryManagerMap[documentVariantInfo] = new ReferenceRegistryManager(_openApiDocumentGenerationSettings); } foreach (var pathToPathItem in paths) { var path = pathToPathItem.Key; var pathItem = pathToPathItem.Value; foreach (var operationMethodToOperation in pathItem.Operations) { var operationMethod = operationMethodToOperation.Key; var operation = operationMethodToOperation.Value; var operationFilterSettings = new OperationFilterSettings { TypeFetcher = typeFetcher, ReferenceRegistryManager = referenceRegistryManagerMap[documentVariantInfo], Path = path, OperationMethod = operationMethod.ToString() }; // Apply all the operation-related filters to extract information related to the operation. // It is important that these are applied before the config filters below // since the config filters may rely on information generated from operation filters. foreach (var operationFilter in _operationFilters) { try { operationFilter.Apply( operation, operationElement, operationFilterSettings); } catch (Exception e) { operationGenerationErrors.Add( new GenerationError { ExceptionType = e.GetType().Name, Message = e.Message } ); } } if (operationConfigElement != null) { // Apply the config-related filters to extract information from the config xml // that can be applied to the operations. foreach (var configFilter in _operationConfigFilters) { try { configFilter.Apply( operation, operationConfigElement, new OperationConfigFilterSettings { OperationFilterSettings = operationFilterSettings, OperationFilters = _operationFilters }); } catch (Exception e) { operationGenerationErrors.Add( new GenerationError { ExceptionType = e.GetType().Name, Message = e.Message } ); } } } // Add the processed operation to the specification document. if (!specificationDocuments.ContainsKey(documentVariantInfo)) { specificationDocuments.Add( documentVariantInfo, new OpenApiDocument { Components = new OpenApiComponents(), Paths = new OpenApiPaths() }); } // Copy operations from local Paths object to the Paths in the specification document. var documentPaths = specificationDocuments[documentVariantInfo].Paths; if (!documentPaths.ContainsKey(path)) { documentPaths.Add( path, new OpenApiPathItem { Operations = { [operationMethod] = operation } }); } else { if (documentPaths[path].Operations.ContainsKey(operationMethod)) { throw new DuplicateOperationException( path, operationMethod.ToString(), documentVariantInfo.Title); } documentPaths[path].Operations.Add(operationMethod, operation); } } } }