Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SwaggerEndPoints configuration section is missing or empty exception #90

Closed
rajeshgithub001 opened this issue Apr 27, 2020 · 7 comments
Closed
Assignees

Comments

@rajeshgithub001
Copy link

I am using SwaggerForOcelot with .net core 3.1 for api gateway.

Our ocelot json is divided into modules like below:-

ocelot.call-log.json
ocelot.column-chooser.json
ocelot.contact-list.json
ocelot.documentation.json
ocelot.global.json
ocelot.inventory-list.json
ocelot.json <= this is generated automatically.
ocelot.swagger.json <=define here swagger related configuration , pls find below

{
"ReRoutes": [
{
"DownstreamPathTemplate": "/api/{everything}",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "xx.xx.xx.xx",
"Port": 6004
}
],
"UpstreamPathTemplate": "{everything}",
"UpstreamHttpMethod": [ "GET", "POST", "PUT", "DELETE" ],
"SwaggerKey": "all"
}
],
"SwaggerEndPoints": [
{
"Key": "all",
"Config": [
{
"Name": "Test API V1",
"Version": "v1",
"Url": "http://xx.xx.xx.xx:6004/swagger/v1/swagger.json"
}
]
}
]
}

On running it giving exception on below line:-

app.UseSwaggerForOcelotUI(Configuration, opt =>
{
opt.PathToSwaggerGenerator = "/swagger/docs";
});

Exception details:-
at Microsoft.AspNetCore.Builder.BuilderExtensions.GetConfiguration(IConfiguration configuration)
at Microsoft.AspNetCore.Builder.BuilderExtensions.<>c__DisplayClass1_0.b__0(SwaggerUIOptions c)
at Microsoft.AspNetCore.Builder.SwaggerUIBuilderExtensions.UseSwaggerUI(IApplicationBuilder app, Action1 setupAction) at Microsoft.AspNetCore.Builder.BuilderExtensions.UseSwaggerForOcelotUI(IApplicationBuilder app, IConfiguration configuration, Action1 setupAction)
at SMARTS2.ApiGateway.Startup.Configure(IApplicationBuilder app, IWebHostEnvironment env) in C:\Users\rajesh.agrawal\source\repos\SMARTS 2.0 API\SMARTS2.0\SMARTS2.ApiGateway\Startup.cs:line 63
at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor, Boolean wrapExceptions)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at Microsoft.AspNetCore.Hosting.ConfigureBuilder.Invoke(Object instance, IApplicationBuilder builder)
at Microsoft.AspNetCore.Hosting.ConfigureBuilder.<>c__DisplayClass4_0.b__0(IApplicationBuilder builder)
at Microsoft.AspNetCore.Hosting.ConventionBasedStartup.Configure(IApplicationBuilder app)

Let me know why this error coming ?

@Burgyn
Copy link
Owner

Burgyn commented Apr 27, 2020

Hi,
unfortunately this package doesn't support this scenario, now.

See #69. @amadard tried support this in issue #79, but without response.

@amadard
Copy link

amadard commented Apr 27, 2020

@rajeshgithub001 I am happy to help! I have the code, I just havent made the time to build out the unit tests and thus havent submitted it as a PR.

You have to replace the AddOcelot() with a custom extension that takes the SwaggerEndPoints into consideration. AddOcelot deserializes all of your individual files into a Model, which is why the SwaggerKey gets lost. I have an extension method replacement and a couple replacement classes to resolve the issue. It is working fine for me, and has been in production for a couple months now.

@rajeshgithub001
Copy link
Author

rajeshgithub001 commented Apr 28, 2020

@rajeshgithub001 I am happy to help! I have the code, I just havent made the time to build out the unit tests and thus havent submitted it as a PR.

You have to replace the AddOcelot() with a custom extension that takes the SwaggerEndPoints into consideration. AddOcelot deserializes all of your individual files into a Model, which is why the SwaggerKey gets lost. I have an extension method replacement and a couple replacement classes to resolve the issue. It is working fine for me, and has been in production for a couple months now.

@amadard Please provide an extension method ?

@amadard
Copy link

amadard commented Apr 28, 2020

First step is to replace the Ocelot FileReRoute, which is why the SwaggerKey is being dropped:

	public class SwaggerFileReRoute: FileReRoute
	{
		public string SwaggerKey { get; set; }
	}

Then we need to replace the FileConfiguration to have the ReRoutes property use our new SwaggerFileReRoute model. This is a full redo, since we cant inherit and replace the ReRoutes property.

	public class SwaggerFileConfiguration
	{
		public List<SwaggerFileReRoute> ReRoutes { get; set; } = new List<SwaggerFileReRoute>();

		public List<FileDynamicReRoute> DynamicReRoutes { get; set; } = new List<FileDynamicReRoute>();

		// Seperate field for aggregates because this let's you re-use ReRoutes in multiple Aggregates
		public List<FileAggregateReRoute> Aggregates { get; set; } = new List<FileAggregateReRoute>();

		public FileGlobalConfiguration GlobalConfiguration { get; set; } = new FileGlobalConfiguration();

		public List<SwaggerEndPointOptions> SwaggerEndPoints { get; set; } = new List<SwaggerEndPointOptions>();
	}

Then we are replacing the AddOcelot(this IConfigurationBuilder builder, string folder, IWebHostEnvironment env) method with our own version that properly uses the above models, and handles the SwaggerEndPoints. This is copy and update of the AddOcelot.

        public static IConfigurationBuilder AddOcelotWithSwaggerSupport(this IConfigurationBuilder builder, string folder, IWebHostEnvironment env)
        {
            string primaryConfigFile = "ocelot.json";

            string globalConfigFile = "ocelot.global.json";

            string SwaggerEndPointsConfigFile = "ocelot.SwaggerEndPoints.json";

            string subConfigPattern = @"^ocelot\.(.*?)\.json$";

            string excludeConfigName = env?.EnvironmentName != null ? $"ocelot.{env.EnvironmentName}.json" : string.Empty;

            var reg = new Regex(subConfigPattern, RegexOptions.IgnoreCase | RegexOptions.Singleline);

            var files = new DirectoryInfo(folder)
                .EnumerateFiles()
                .Where(fi => reg.IsMatch(fi.Name) && (fi.Name != excludeConfigName))
                .ToList();

            var fileConfiguration = new SwaggerFileConfiguration();

            foreach (var file in files)
            {
                if (files.Count > 1 && file.Name.Equals(primaryConfigFile, StringComparison.OrdinalIgnoreCase))
                {
                    continue;
                }

                var lines = File.ReadAllText(file.FullName);

                var config = JsonConvert.DeserializeObject<SwaggerFileConfiguration>(lines);

                if (file.Name.Equals(globalConfigFile, StringComparison.OrdinalIgnoreCase))
                {
                    fileConfiguration.GlobalConfiguration = config.GlobalConfiguration;
                }

                if (file.Name.Equals(SwaggerEndPointsConfigFile, StringComparison.OrdinalIgnoreCase))
                {
                    fileConfiguration.SwaggerEndPoints = config.SwaggerEndPoints;
                }

                fileConfiguration.Aggregates.AddRange(config.Aggregates);
                fileConfiguration.ReRoutes.AddRange(config.ReRoutes);
            }

            var json = JsonConvert.SerializeObject(fileConfiguration);

            File.WriteAllText(primaryConfigFile, json);

            builder.AddJsonFile(primaryConfigFile, false, false);

            return builder;
        }

This requires your SwaggerEndPoints be in a file named "ocelot.SwaggerEndPoints.json".

Then you call that extension method in replacement of AddOcelot()

  webBuilder
  .ConfigureAppConfiguration((hostingContext, config) =>
  {
	  config
		  .SetBasePath(hostingContext.HostingEnvironment.ContentRootPath)
		  .AddOcelotWithSwaggerSupport(folder, hostingContext.HostingEnvironment);
  })

@rajeshgithub001
Copy link
Author

First step is to replace the Ocelot FileReRoute, which is why the SwaggerKey is being dropped:

	public class SwaggerFileReRoute: FileReRoute
	{
		public string SwaggerKey { get; set; }
	}

Then we need to replace the FileConfiguration to have the ReRoutes property use our new SwaggerFileReRoute model. This is a full redo, since we cant inherit and replace the ReRoutes property.

	public class SwaggerFileConfiguration
	{
		public List<SwaggerFileReRoute> ReRoutes { get; set; } = new List<SwaggerFileReRoute>();

		public List<FileDynamicReRoute> DynamicReRoutes { get; set; } = new List<FileDynamicReRoute>();

		// Seperate field for aggregates because this let's you re-use ReRoutes in multiple Aggregates
		public List<FileAggregateReRoute> Aggregates { get; set; } = new List<FileAggregateReRoute>();

		public FileGlobalConfiguration GlobalConfiguration { get; set; } = new FileGlobalConfiguration();

		public List<SwaggerEndPointOptions> SwaggerEndPoints { get; set; } = new List<SwaggerEndPointOptions>();
	}

Then we are replacing the AddOcelot(this IConfigurationBuilder builder, string folder, IWebHostEnvironment env) method with our own version that properly uses the above models, and handles the SwaggerEndPoints. This is copy and update of the AddOcelot.

        public static IConfigurationBuilder AddOcelotWithSwaggerSupport(this IConfigurationBuilder builder, string folder, IWebHostEnvironment env)
        {
            string primaryConfigFile = "ocelot.json";

            string globalConfigFile = "ocelot.global.json";

            string SwaggerEndPointsConfigFile = "ocelot.SwaggerEndPoints.json";

            string subConfigPattern = @"^ocelot\.(.*?)\.json$";

            string excludeConfigName = env?.EnvironmentName != null ? $"ocelot.{env.EnvironmentName}.json" : string.Empty;

            var reg = new Regex(subConfigPattern, RegexOptions.IgnoreCase | RegexOptions.Singleline);

            var files = new DirectoryInfo(folder)
                .EnumerateFiles()
                .Where(fi => reg.IsMatch(fi.Name) && (fi.Name != excludeConfigName))
                .ToList();

            var fileConfiguration = new SwaggerFileConfiguration();

            foreach (var file in files)
            {
                if (files.Count > 1 && file.Name.Equals(primaryConfigFile, StringComparison.OrdinalIgnoreCase))
                {
                    continue;
                }

                var lines = File.ReadAllText(file.FullName);

                var config = JsonConvert.DeserializeObject<SwaggerFileConfiguration>(lines);

                if (file.Name.Equals(globalConfigFile, StringComparison.OrdinalIgnoreCase))
                {
                    fileConfiguration.GlobalConfiguration = config.GlobalConfiguration;
                }

                if (file.Name.Equals(SwaggerEndPointsConfigFile, StringComparison.OrdinalIgnoreCase))
                {
                    fileConfiguration.SwaggerEndPoints = config.SwaggerEndPoints;
                }

                fileConfiguration.Aggregates.AddRange(config.Aggregates);
                fileConfiguration.ReRoutes.AddRange(config.ReRoutes);
            }

            var json = JsonConvert.SerializeObject(fileConfiguration);

            File.WriteAllText(primaryConfigFile, json);

            builder.AddJsonFile(primaryConfigFile, false, false);

            return builder;
        }

This requires your SwaggerEndPoints be in a file named "ocelot.SwaggerEndPoints.json".

Then you call that extension method in replacement of AddOcelot()

  webBuilder
  .ConfigureAppConfiguration((hostingContext, config) =>
  {
	  config
		  .SetBasePath(hostingContext.HostingEnvironment.ContentRootPath)
		  .AddOcelotWithSwaggerSupport(folder, hostingContext.HostingEnvironment);
  })

Thanks a lot.

@Burgyn
Copy link
Owner

Burgyn commented May 1, 2020

hi guys,
please can you provide PR (it can help others)? It can be without tests, I can write them.

@amadard
Copy link

amadard commented May 1, 2020

Sure thing! I will get it done this weekend.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants