swagger/index.html shows a blank page (asp.net core) - asp.net-core

I am writing a web api in ASP.NET CORE for the data models Package and Content. They are originally from MSSQL so I connected to the db server successfully. After writing http requests in the controllers, when I ran the project to test, it takes me to swagger/index.html that shows a blank page, I have no idea why.
Here is my program.cs
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
//OperationsContext is a db context that has both content and package dbcontext
builder.Services.AddDbContext<OperationsContext>(x => x.UseSqlServer(connectionString));
/*builder.Services.AddMvc();
builder.Services.AddHttpContextAccessor();*/
builder.Services.AddScoped<IContentRepository, ContentRepository>();
builder.Services.AddScoped<IPackageRepository, PackageRepository>();
var app = builder.Build();
// Configure the HTTP request pipeline.
app.UseSwagger();
app.UseSwaggerUI(c =>
{
if (app.Environment.IsDevelopment() || app.Environment.IsProduction())
{
c.SwaggerEndpoint("/swagger/Package/swagger.json", "Package v1");
}
else
{
// To deploy on IIS
c.SwaggerEndpoint("/swagger/Package/swagger.json", "Package v1");
}
});
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
I am assuming it's the program.cs, but there are no issues when I ran it. Does anyone know why?

Swagger UI does not support Internet Explorer. Use Chrome, Firefox, Safari, or Edge instead.

Related

ASP.NET Core 6 MVC app works just fine on local machine, but one method fails on IIS

I am trying to build an ASP.NET Core 6 MVC app. Everything works fine on my local machine. But when I publish to IIS Server, one of my post operations fails.
In the event viewer I saw this error:
System.Security.Cryptography.CryptographicException: The key {be1734ec-d82b-46c0-b5a6-ffff2bc4a207} was not found in the key ring
So I investigated and to sum up changed my Program.cs like this;
using BusinessLogicLayer;
using DBLayer;
using ExcelOperations;
using HashOperations;
using Microsoft.AspNetCore.DataProtection;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllersWithViews();
builder.Services.AddSession(options =>
{
options.IdleTimeout = TimeSpan.FromMinutes(10);
});
builder.Services.AddDataProtection()
//.SetApplicationName("App Name")
.PersistKeysToFileSystem(new DirectoryInfo(#"C:\test\"))
.ProtectKeysWithDpapi();
builder.Services.AddMemoryCache();
builder.WebHost.UseIISIntegration();
builder.Services.AddScoped<IExcelHelper, ExcelHelper>();
builder.Services.AddScoped<ISQLDBHelper, SQLDBHelper>();
builder.Services.AddScoped<IHashHelper, HashHelper>();
builder.Services.AddScoped<IExcelBusiness, ExcelBusiness>();
builder.Services.AddScoped<ILoginBusiness, LoginBusiness>();
builder.Services.AddScoped<IinsertConfirmation, insertConfirmation>();
builder.Services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
builder.Services.AddScoped<IInsertOperationShowData, InsertOperationShowData>();
builder.Services.AddScoped<IUpdateOperationShowData, UpdateOperationShowData>();
builder.Services.AddScoped<IDeleteOperationShowData, DeleteOperationShowData>();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
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.UseAuthorization();
app.UseSession();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
app.Run();
I see something is creating on c:\test. But when it comes to last operation, it works fine on my local, but fails on IIS 10. After adding dataprotection, no error messages is shown, but the operation is still not working on IIS. On my local computer everything is working fine.
The steps on code at controller side is like this;
$.post("/Home/confirmDataUpload", function(data) {
#switch (Model)
{
case List<ExcelInsertConfirmationModel>:
<text>
window.location = "/Home/insertOperationShowData";
</text>
break;
case List<ExcelUpdateConfirmationModel>:
<text>
window.location = "/Home/updateOperationShowData";
</text>
break;
case List<ExcelDeleteConfirmationModel>:
<text>
window.location = "/Home/deleteOperationShowData";
</text>
break;
default:
break;
}
}).fail(function(xhr, status, error) { alert("Error!!! " + xhr.responseText); });
Doing POST operation to this method and according to this page's data model which I take dynamic I am routing to an other page.
This is the controller method that i post;
[CheckSession]
[HttpPost]
public JsonResult confirmDataUpload()
{
int result =_excelBusiness.insertExcelRowsToDB((List<string>)_memoryCache.Get("insertList"));
return (result > 0) ? new JsonResult("ok") : new JsonResult("notok");
}
In this method i am inserting to DB and routing to results page. On my local everything is working fine but on IIS 10 with Windows Server 2019 this method is not going to DB. Looks like doing nothing.
In my web.config I changed the value of stdoutLogEnabled from false to true but still no messages.
On the IIS side, I changed LoadUserProfile from false to true but still no luck.
What can be happening on IIS side and how can I resolve it?

API Gateway Ocelot .Net Core 6.1 Setup

The .Net 6 have removed the Start up Class and i am not able to find out how to configure Ocelot in new .Net 6 structure. I have found two methos
using Ocelot.DependencyInjection;
using Ocelot.Middleware;
var builder = WebApplication.CreateBuilder(args);
builder.Configuration.AddOcelot()// 1.ocelot.json goes where?
// Add services to the container.
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddOcelot(); // 2.what is the use of this
Let me know Please
Add json file called ocelot.json in your project.
Then do configure like this in Program.cs:
IConfiguration configuration = new ConfigurationBuilder()
.AddJsonFile("ocelot.json")
.Build();
var builder = WebApplication.CreateBuilder(args);
//.....
builder.Services.AddOcelot(configuration);
var app = builder.Build();
//........
app.UseOcelot();
//......
You probably already have solved this, so this is meant for all the other developers looking for a solution to this. Below are two ways of adding the Ocelot configuration.
Add a new JSON file in your project named ocelot.json and add your configuration for ocelot inside.
The file ocelot.json has to be registered in Program.cs in order for Ocelot to load the configuration for your API Gateway.
Below are two examples of how you can register your Ocelot configuration.
1. Adding Ocelot configuration without environment check
using Ocelot.DependencyInjection;
using Ocelot.Middleware;
var builder = WebApplication.CreateBuilder(args);
IConfiguration configuration = new ConfigurationBuilder()
.AddJsonFile("ocelot.json")
.Build();
builder.Services.AddOcelot(configuration);
var app = builder.Build();
await app.UseOcelot();
app.MapGet("/", () => "Hello World!");
app.Run();
As you can see we load the configuration from ocelot.json by using .ConfigurationBuilder(). We then parse the configuration to the method for adding Ocelot to the service container before registering it's middleware.
2. Add Ocelot configuration for the current environment
I tend to have multiple environments for production, testing, local development, etc... instead of re-writing/updating the configuration loader with the specific configuration file for Ocelot, we can do it by checking what environment we are running.
using Ocelot.DependencyInjection;
using Ocelot.Middleware;
var builder = WebApplication.CreateBuilder(args);
IConfiguration configuration = new ConfigurationBuilder()
.AddJsonFile($"ocelot.{builder.Environment.EnvironmentName}.json", true, true)
.Build();
builder.Services.AddOcelot(configuration);
var app = builder.Build();
await app.UseOcelot();
app.MapGet("/", () => "Hello World!");
app.Run();
In the code above we use IHostEnvironment to get the current environment name. We can then use string interpolation to dynamically insert the environment name into the string of our ocelot configuration file.
For this to work, you would have to add a new configuration file for each environment like this:
ocelot.json
├─ ocelot.Development.json
├─ ocelot.Local.json
├─ ocelot.Test.json
You need to declare direct from your program.cs you add your Ocelot json file in bulder.configuration, than in services add the Ocelot reference, and in the end start the intance app.Ocelot().wait();
Here is an example, hope it helps
using Ocelot.DependencyInjection;
using Ocelot.Middleware;
var builder = WebApplication.CreateBuilder(args);
builder.Configuration.AddJsonFile("ocelot.json");
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddOcelot();
var app = builder.Build();
//if (app.Environment.IsDevelopment())
//{
app.UseSwagger();
app.UseSwaggerUI();
//}
app.UseHttpsRedirection();
app.UseOcelot().Wait();
app.UseAuthorization();
app.MapControllers();
app.Run();

Asp.Net Core configure Identity authentication middleware properly

Requirement is that I have MVC & WebAPI in the project. MVC views will be delivered for initial
rendering like Login, base views of features (ex:- Users/Index, Dashboard/Index etc..) Web APIs will be used for other work within these views via AJAX with JWT.
I am using Asp.Net core Identity for user management related work running on .Net 5.0
I am confused with configuring multiple identity schemes and the proper configuration of authentication/authorization pipeline in conigureservices() & configure() in startup.
To configure multiple auth schemes I referred to https://stackoverflow.com/a/64887479/2058413 since it's done using same versions that I use. So my startup methods are below which is similar to the code in that thread.
public void ConfigureServices(IServiceCollection services)
{
string connectionString = Configuration.GetConnectionString("default");
services.AddDbContext<AppDBContext>(c => c.UseSqlServer(connectionString));
services.AddIdentity<IdentityUser, IdentityRole>()
.AddEntityFrameworkStores<AppDBContext>();
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(x =>
{
x.LoginPath = "/Account/Login";
x.ExpireTimeSpan = TimeSpan.FromMinutes(10d);
x.AccessDeniedPath = "/Account/Register";
})
.AddJwtBearer(x =>
{
x.RequireHttpsMetadata = false;
x.SaveToken = true;
x.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes("123456")),
ValidateIssuer = false,
ValidateAudience = false
};
});
services.AddAuthorization(options =>
{
var defaultAuthorizationPolicyBuilder = new AuthorizationPolicyBuilder(CookieAuthenticationDefaults.AuthenticationScheme, JwtBearerDefaults.AuthenticationScheme);
defaultAuthorizationPolicyBuilder = defaultAuthorizationPolicyBuilder.RequireAuthenticatedUser();
options.DefaultPolicy = defaultAuthorizationPolicyBuilder.Build();
});
services.AddControllersWithViews();
}
My App configure method is below
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
Then the test method in controller(where user should get redirected to after authentication) is below
[Authorize(AuthenticationSchemes = CookieAuthenticationDefaults.AuthenticationScheme)]
public IActionResult Index()
{
return View();
}
To my understanding the order of the pipeline configuration is correct. Now here are the problems I face.
As specified in .AddCookie(option=>) , user doesn't get redirected to login page. However, if I remove the JwtBearerDefaults.AuthenticationScheme from the services.AddAuthorization(…) it gets redirected to login page properly. Why is that?
So I remove JwtBearerDefaults.AuthenticationScheme; which takes me to login and after successful login I can see that HttpContext.User.Identity.IsAuthenticated is set to true. But it doesn't redirect to Home/Index. No errors thrown and in browser console [network tab] it shows a 302 and redirect back to login. Since I have added [Authorize(AuthenticationSchemes = CookieAuthenticationDefaults.AuthenticationScheme)] to Index method in HomeController, I tried removing the scheme and adding [Authorize] and tried again. Still it gets redirected to login page. This is another thing I am confused about.
So I removed everything related to dual scheme authentication and left the ConfigureService() with below code
string connectionString = Configuration.GetConnectionString("default");
services.AddDbContext<AppDBContext>(c => c.UseSqlServer(connectionString));
services.AddIdentity<IdentityUser, IdentityRole>()
.AddEntityFrameworkStores<AppDBContext>();
services.AddControllersWithViews();
Now everything works fine (redirection to login if not authenticated and also redirects to /Home/Index after authorization).
I went through below links as well about multi scheme authentication, but I am still confused with this pipeline configuration.
ASP.NET Core WebAPI Cookie + JWT Authentication
https://wildermuth.com/2017/08/19/Two-AuthorizationSchemes-in-ASP-NET-Core-2
https://mitchelsellers.com/blog/article/using-multiple-authentication-authorization-providers-in-asp-net-core
I need help only to this multi-scheme authentication pipeline configuration part.
Ok, after some research the main issue was;
I have mixed up old ways of registering services in StartUp (asp.net core 3.x). So had to clear up all those. Resources that helped me to do that;
Migrate from ASP.NET Core 3.1 to 5.0
ASP.NET Core Middleware
This cleaned up a lot of unnecessary code since in .Net 5 there were some shortcuts that could be used.
Order of service registrations. This may depend on what kind of services you are using, but in my case the order was something like below:
AddIdentity
setup Cookie & JWT authentication c)
My Multitenant stuff
AddCors
AddModules (will be option for some of you. I use it to load plugins dynamically)
Other stuff (However, even in these places the order might matter depending on
what you do)
The other thing was, I had to remove ConfigureApplicationCookie() since AddIdentity seems to be doing that. Also in AddAuthorization() earlier I had code to specify what are the default schemes i wanted to use (Cookie & JWT). But now I had to remove all that. Reason is Identity takes over the cookie scheme and when I specify below, JWTAuth takes over.
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
Generally setting up Startup properly seems to be tricky depending on different services you use. Order will matter

ASP.Net Core spa pre-rendering with angular universal works locally but not on server

I'm trying to set up angular universal on angular7 with asp.net core 2.1. The prerendering works perfectly on a local build but does not add code to the page source on a server in production with no errors or logs.
Due to the lack of logs I suspect this is because the server module is not loaded/ started but I have no idea why. Is this something that should be added into the web config?
I am using a windows shared plesk server which supports node.js and IIS Node. Here is a snippet from my Startup.cs
app.UseSpa(spa =>
{
spa.Options.StartupTimeout = new System.TimeSpan(0, 0, 1000);
spa.Options.SourcePath = "ClientApp";
spa.UseSpaPrerendering(options =>
{
options.BootModulePath = $"{spa.Options.SourcePath}/dist-server/main.js";
options.BootModuleBuilder = env.IsDevelopment() ? new
AngularCliBuilder(npmScript: "build:ssr") : null;
options.ExcludeUrls = new[] { "/sockjs-node" };
});
if (env.IsDevelopment())
{
spa.UseAngularCliServer(npmScript: "start");
}
});
I eventually realised I had the line app.UseStaticFiles(); as well as app.UseSpaStaticFiles in Startup.cs. Removing app.UseStaticFiles(); solved this issue. However, I am still not sure why this wasn't causing issues on a local build.
I believe you are misusing the prerendering middleware.
About prerendering: Represents the ability to build a Single Page Application (SPA) on demand so that it can be prerendered. This is only intended to be used at development time. In production, a SPA should already have been built during publishing.
You should hide that piece of code behind:
env.IsDevelopment()
Read more here

Swagger integration into Bot Framework 4

I'm trying to integrate swagger / swashbuckler into a project with UI into a project based on the latest Bot Framework V4 template. However it seems I'm getting only 500 http status codes when I try to navigate to /swagger or /swagger/v1/swagger.json.
The things I'm trying to add are in ConfigureServices:
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new Info { Title = "My API", Version = "v1" });
});
and in Configure:
loggerFactory = loggerFactory;
app.UseDefaultFiles()
.UseStaticFiles()
.UseBotFramework();
app.UseSwagger()
.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
});
I also tried to put the UseSwagger parts before the other but then the bot didn't work anymore as well. Likely there's some collision in endpoints being generated by the different parts but I'd really like to get that swagger part working.
The problem is Swagger requires MVC features to work and it looks like you're using the default templates for a bot which don't actually need MVC so it's not added to avoid the massive overhead that feature brings to the table.
So, you need to add the following in ConfigureServices:
services.AddMvc();
And then the following to Configure. NOTE: The order of the UseXXX calls do matter, but the order you're doing them in right now is fine and I would just do this:
app.UseDefaultFiles()
.UseStaticFiles()
.UseBotFramework()
.UseMvc()
.UseSwagger()
.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
});