.NET Core 3.1 - Swagger not loadig - asp.net-core

I am trying to implement Swagger in my WebApi. However, it is not working. The issue is that swagger.json loads forever. When I try to go to /swagger/v1/swagger.json, it loads forever and my CPU usages spikes to 100%.
This is my configuration:
public class Startup
{
...
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
...
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo
{
Version = "v1",
Title = "ToDo API"
});
});
...
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IServiceProvider services)
{
...
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
});
// Setup the endpoints.
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller}/{action}/{id?}");
endpoints.MapHub<HomeHub>("/homehub");
});
}
}
I of course already looked around on the internet, but could not find any solution. I do not get any errors, so what could be the issue?
Update:
I have tried generating the json file with the CLI, and same issue. It just loads and nothing happens. Besides taking 24gb of memory...

I believe that one of your controller or class causes this error. It looks like swagger tries to load something recursively.
I suggest you to use memory profiler (like dotMemory) to find out what is going on (what creates this memory leak)
Another workaround is to comment out all your controllers and enable them one by one until you find the erroneous code.
Also you may want to check this Answer

Related

How to tell when a self-hosted ASP.NET Core application is ready to receive requests?

I need to launch worker processes that communicate using ASP.NET Core Web API. I need to know when I can start sending requests to that process. The only options I see so far are to have the worker call the parent process API when it has finished configuring or poll the worker with an "are you alive" request.
Is there any built in mechanism for this? Any better patterns or designs?
In general, after the application is started successfully, you will be able to send request.
For Application Start event, you could try IHostApplicationLifetime in .net core 3.0, if you are using previous version, you could try IApplicationLifetime which will be obsolete in future version.
Here is a demo which is used to register event while application is started.
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews().AddNewtonsoftJson();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IHostApplicationLifetime hostApplicationLifetime)
{
hostApplicationLifetime.ApplicationStarted.Register(() => {
Console.WriteLine("Application is Started");
});
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
// 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.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
}

Why am I looking at JSON, not my nice Swagger UI?

I've installed swashbuckle on on a clean asp.net core web api project following these instructions. My startup class is below. You can see I've added AddSwaggerGen(), UseSwagger() and UseSwaggerUI().
When I visit https://localhost:44334/swagger/v1/swagger.json, instead of seeing the swagger UI I expect, I've got a pile of JSON, starting {"swagger":"2.0","info":{"version":"v1","title":"MoqOcr"}...
What am I missing ?
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
// sby
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new Info { Title = "MoqOcr", Version = "v1" });
});
}
// 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();
}
else
{
app.UseHsts();
}
// sby
// Enable middleware to serve generated Swagger as a JSON endpoint.
app.UseSwagger();
// Enable middleware to serve swagger-ui (HTML, JS, CSS, etc.),
// specifying the Swagger JSON endpoint.
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
c.RoutePrefix = string.Empty;
});
//app.UseHttpsRedirection();
app.UseMvc();
}
}
I have checked your configuration for Swagger in Startup.cs and there seemed no unexpected thing to setup swagger to me. The only thing that pops in my mind is that you are mistaken the SwaggerEndpoint setting which indicates to you (I suppose) that you can access your Swagger UI from that url but it holds a json to build and configure that UI page. Fair enough but you should try https://localhost:44334/swagger
or https://localhost:44334/swagger/index.html to see your Swagger UI page. Hope this solves your problem.

ASP.NET Core 2.x OnConfiguring get connectionstring string from appsettings.json

Just started messing with ASP.NET Core, pretty impressive so far. In the code generated,(see below). I want to change the hardcoded connection string to get it from the appsettings.json file.
This is apparently impossible. I haven't found a single example that works (or even builds).
What's going on??
Please help
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
#warning To protect potentially sensitive information in your connection string, you should move it out of source code. See http://go.microsoft.com/fwlink/?LinkId=723263 for guidance on storing connection strings.
optionsBuilder.UseSqlServer("Server=xxxxxxx;Database=xxxxx;Trusted_Connection=True;");
}
}
The link provided solves the problem in one area but doesn't work here in OnConfiguring. What am I doing wrong ?
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.Configure<CookiePolicyOptions>(options =>
{
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
var connection = Configuration.GetConnectionString("ConnectionName");
services.AddDbContext<SurveyContext>(options => options.UseSqlServer(connection));
}
// 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();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
}
In the startup class of a .NET Core project you usually register this in the ConfigureServices function.
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<YourContext>(options => options.UseSqlServer(connection));
}
When you are in the startup class of a .NET Core it is no problem to read the values from appsettings.json.
You could read more at Microsoft, i.e. here: https://learn.microsoft.com/en-us/ef/core/get-started/aspnetcore/existing-db
In the place where you want to access the appsettings.json,
JToken jAppSettings = JToken.Parse(
File.ReadAllText(Path.Combine(Environment.CurrentDirectory,
"appsettings.json")));
Now since you have the object, you can access its contents.
Let me know if it works.
When you use the Scaffold-DbContext, by default it hard codes your string into the DbContext class (so it works out of the box). You will need to register your DbContext in your startup class to proceed. To set this up, you can check the instructions in this answer.
Note that the Configuration property directly connects to your appsettings.json and several other locations. You can read more about it in this documentation. While you can always use the appsettings.json file, it is generally recommended to have your secure secrets in an external json file outside your source code. The best solution for this during development is using the secret manager. The easiest way to use this is right click on your project on visual studio and select "manage user secrets". This will open a json file that is already connected to your Configuration object.
Once this is set up, you need to use dependency injection to access your db context.
public class HomeController : Controller
{
public HomeController(SurveyContext context)
{
// you can set the context you get here as a property or field
// you can use visual studio's shortcut ctrl + . when the cursor is on "context"
// you can then use the context variable inside your actions
}
}
When you use using, it creates a new connection each time. Using injection makes sure only one connection is created per request no matter how many times it is used.

AspNETCore Odata Batching

I'm having some issues trying to configure batching for OData on an AspNETCore Web Application. I've searched everywhere (almost) and couldn't find a proper answer. I'm not sure that the current AspNetCore.Odata version 7.0.0 which is still beta has support for batching.
As far as I am concerned, configuring batching seems impossible now since the MapODataServiceRoute method (from the AspNetCore assemply) doesn't seem to receive any ODataBatchHandler as in .NET common Odata.
app.UseMvc(routes =>
{
routes.Count().Filter().OrderBy().Expand().MaxTop(null);
routes.MapODataServiceRoute("odata", "odata", builder.GetEdmModel()); //Doesn't receive any ODataBatchHandler
routes.EnableDependencyInjection();
});
If someone came across this batching issue for Odata core, some advice would be pretty helpful. Thanks!
Try replace the existing ConfigureServices and Configure methods with the following code:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddOData();
}
public void Configure(IApplicationBuilder app)
{
var builder = new ODataConventionModelBuilder(app.ApplicationServices);
builder.EntitySet<Product>("Products");
app.UseMvc(routeBuilder =>
{
routeBuilder.Select().Expand().Filter().OrderBy().MaxTop(100).Count();
routeBuilder.MapODataServiceRoute("ODataRoute", "odata", builder.GetEdmModel());
routeBuilder.EnableDependencyInjection();
});
}

Asp.net core site hangs after about 50 requests

I use asp net core 2.0 and faced very strange behavior (at least I see it locally with IIS express). I open site page then press Refresh button about 50 times and site starts hanging, processing of request takes about 40 seconds. Then after about 5 minutes of idle I refresh page again and everything works fast. Next ~50 requests and again it hangs. I'm very confused with that and don't have ideas what is the reason and how to troubleshoot it. I removed all things from code and rest only base code and it's still reproducable.
My Startup class looks so:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
//public void ConfigureServices(IServiceCollection services)
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.AddMvc();
return services.BuildServiceProvider();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.Use(async delegate(HttpContext context, Func<Task> next)
{
await next.Invoke();
});
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseBrowserLink();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
}
Controller actions don't do anything they just return View. In debugging I often see that it hangs on "await next.Invoke();" line (I've added this delegate only for debugging) but I'm not sure that problem is exactly in action executing.
Maybe anybody knows what can be a reason or how I can troubleshoot it?
Looks like the problem was solved in unexpected way - I updated Visual Studio and as I saw IIS was also updated together with it.