Why am I looking at JSON, not my nice Swagger UI? - asp.net-core

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.

Related

Http Post in Orchard Core asp net core Web App returns bad request

I'm using Orchard core in asp net core web app project. I have a controller with two simple get and post Apis. As I'm using OrchardCore the Startup.cs file has different config and I dont use services.AddControllers() in configureServices.
Every thing is fine untill I'm using HttpGet. But when I want to have an Api with HttpPost postMan says badRequest. So I Added services.AddControllers() in Startup.cs and the post Api was fine in post Man but the orchard project says I have multipe Endpoints.
I used services.AddMvc().AddNewtonsoftJson(), and every thing was fine but the admin page didn't load and had error as below:
InvalidOperationException: The view 'Index' was not found. The
following locations were searched:
/Areas/OrchardCore.AdminDashboard/Views/Dashboard/Index.cshtml
/Areas/OrchardCore.AdminDashboard/Views/Shared/Index.cshtml
/Views/Shared/Index.cshtml /Pages/Shared/Index.cshtml
I wold appreciate it if you can help me how to call Post Api.
here is my code:
[HttpPost("post")]
public Task<string> post()
{
return Task.FromResult("hiPost");
}
[HttpGet("get")]
public Task<string> get()
{
return Task.FromResult("hiGet");
}
and this is my startup.cs
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
//services.AddControllers();
services.AddOrchardCms();
services.AddMediatR(typeof(SelectedWebSiteBlogQueryHandler).Assembly);
services.AddAutoMapper(typeof(Startup));
services.AddCors();
services.AddMvc().AddNewtonsoftJson();
}
public void Configure(IApplicationBuilder app, IHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseCors(o => o.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod());
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseOrchardCore();
}
}
You are probably missing an IgnoreAntiForgeryToken attribute on your controller.
AntiForgery is enabled by default by OrchardCore
For an ApiController in OrchardCore I would expect to see the controller decorated as follows.
[ApiController]
[Authorize(AuthenticationSchemes = "Api"), IgnoreAntiforgeryToken, AllowAnonymous]
However this depends if you are using the OpenId module to authenticate with, or simply need to post to a normal controller, without an AuthenticationScheme
Depending on what you are actually posting from in real life, it may be better to supply an anti forgery token as part of your post.

How to resolve Request to Long error in Asp.Net Core Azure B2C Configuraiton?

I am new to Asp.Net Core identity.
I have configured the startup as per below. When I run the code in a normal and incognito browser I get the below error.
I have cleared cookies as previous questions have suggested. What is interesting is a high number of cookies get created when loading the sign screen.
My issue is similar to those described in the below old articles. Both solutions seem outdated.
https://www.javaer101.com/en/article/18781756.html
https://blog.bitscry.com/2018/09/19/azure-ad-request-too-long/
using d365fl.DocumentGenerator.blazor_frontend.Data;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.Mvc.Authorization;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Identity.Web;
using Microsoft.IdentityModel.Logging;
namespace d365fl.DocumentGenerator.blazor_frontend
{
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.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
ConfigureIdentiy(services);
services.AddRazorPages();
services.AddServerSideBlazor();
services.AddSingleton<WeatherForecastService>();
}
private void ConfigureIdentiy(IServiceCollection services)
{
services.AddMicrosoftIdentityWebAppAuthentication(Configuration, "AzureAdB2C");
services.AddControllersWithViews(options =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
options.Filters.Add(new AuthorizeFilter(policy));
});
services.Configure<OpenIdConnectOptions>(Configuration.GetSection("AzureAdB2C"));
}
// 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();
IdentityModelEventSource.ShowPII = true;
}
else
{
app.UseExceptionHandler("/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.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapBlazorHub();
endpoints.MapFallbackToPage("/_Host");
});
}
}
}
EDIT 1 - HTTP Request from Developer Toolbar
EDIT 2 - Screen Shot of Cookie data from Developer Toolbar / Network Tab
As we discussed in the comment, the issue is cause by too many cookies.
Please clear your cookies and modify your code to avoid endless loops and back and forth requests.
See this answer for more details.

Problem in enabling CORS in asp net core web api v3.0

I am using asp net core 3.0 in my web API project. I have created various API's and all are accessible via Swagger or Postman. But when trying to access the same via any other client like React, Method not allowed (405 error code) is received. On investing further, I find out that at first, OPTION request is received from the React application and the net core web API application is giving the 405 status code. Further, I find out that I need to enable all the methods as well as origins from the net core application to accept all types of requests otherwise it will not accept OPTION request. To achieve this, I enabled CORS policy in startup.cs file but still had no luck. Following is my startup.cs file:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
var elasticUri = Configuration["ElasticConfiguration:Uri"];
Log.Logger = new LoggerConfiguration()
.Enrich.FromLogContext()
.Enrich.WithExceptionDetails()
.WriteTo.Elasticsearch(new ElasticsearchSinkOptions(new Uri(elasticUri))
{
MinimumLogEventLevel = LogEventLevel.Verbose,
AutoRegisterTemplate = true,
})
.CreateLogger();
}
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<IISServerOptions>(options =>
{
options.AutomaticAuthentication = false;
});
services.Configure<ApiBehaviorOptions>(options =>
{
//To handle ModelState Errors manually as ApiController attribute handles those automatically
//and return its own response.
options.SuppressModelStateInvalidFilter = true;
});
services.AddCors(options =>
{
options.AddPolicy("CorsPolicy",
builder => builder.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader());
});
services.AddControllers(options =>
{
//To accept browser headers.
options.RespectBrowserAcceptHeader = true;
}).
AddNewtonsoftJson(options =>
{
// Use the default property (Pascal) casing
options.SerializerSettings.ContractResolver = new DefaultContractResolver();
options.SerializerSettings.NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore;
}).
AddJsonOptions(options =>
{
//Not applying any property naming policy
options.JsonSerializerOptions.PropertyNamingPolicy = null;
options.JsonSerializerOptions.IgnoreNullValues = true;
}).
AddXmlSerializerFormatters().
AddXmlDataContractSerializerFormatters();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory)
{
app.UseCors("CorsPolicy");
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
// 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");
});
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
//Configuring serilog
loggerFactory.AddSerilog();
}
}
I tried testing the same API with the OPTIONS method from POSTMAN. It is also giving the Http Status Code as 405. But when trying to access the same request using the POST method, I received the response successfully.
Is there anything wrong with the above code or something wrong with the order of middlewares being called in Configure().
Try to add extension method and modifying your startup class:
Extension method:
public static void AddApplicationError(this HttpResponse response, string
message)
{
response.Headers.Add("Application-Error", message);
response.Headers.Add("Access-Control-Expose-Headers", "Application-Error");
response.Headers.Add("Access-Control-Allow-Origin", "*");
}
Startup.cs :
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler(builder =>
{
builder.Run(async context =>
{
context.Response.StatusCode = (int)
HttpStatusCode.InternalServerError;
var error = context.Features.Get<IExceptionHandlerFeature>();
if (error != null)
{
context.Response.AddApplicationError(error.Error.Message);
await context.Response.WriteAsync(error.Error.Message);
}
});
});
}
P.S. in my case I had scenario also returning 405 status error, cause was, similar action methods I used and there are conflicted
For ex:
[HttpGet]
public ActionResult GetAllEmployees()
[HttpGet]
public ActionResult GetCustomers()
Hope this will help at least to show exact error message
You need to add Cors in Startup.cs file under your web api project
add this variable in Startup.cs
readonly string MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
add services.AddCors before services.AddControllers() in the method ConfigureServices in file Startup.cs:
services.AddCors(options =>
{
options.AddPolicy(MyAllowSpecificOrigins,
builder =>
{
builder.WithOrigins("http://localhost:4000",
"http://www.yourdomain.com")
.AllowAnyHeader()
.AllowAnyMethod();
});
});
services.AddControllers();
*** You can pass only * to allow all instead of passing http://localhost:4000","http://www.yourdomain.com in the WithOrigins method
add app.UseCors before app.UseAuthentication() in the method Configure in file Startup.cs:
app.UseCors(MyAllowSpecificOrigins);
Check this Microsoft help
Try this:
app.UseCors(policy =>
policy.WithOrigins("https://localhost:PORT", "https://localhost:PORT")
.AllowAnyMethod()
.WithHeaders(HeaderNames.ContentType)
);

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?}");
});
}
}

Query parameter routing with asp .net core

I'd like to use url query parameter instead of path parameter using .net core API.
controller
[Route("api/[controller]/[action]")]
public class TranslateController : Controller
{
[HttpGet("{languageCode}")]
public IActionResult GetAllTranslations(string languageCode)
{
return languageCode;
}
}
startup.cs is using only default settings
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddMvc()
.AddJsonOptions(jsonOptions =>
{
jsonOptions.SerializerSettings.NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore;
jsonOptions.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
jsonOptions.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
});
services.AddLogging();
services.AddSingleton<IConfiguration>(Configuration);
services.AddSwaggerGen(c =>
{
c.SingleApiVersion(new Info
{
Version = "v1",
Title = "Translate API",
Description = "bla bla bla description",
TermsOfService = "bla bla bla terms of service"
});
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
app.UseMvc();
app.UseSwagger();
app.UseSwaggerUi();
}
my swagger request looks like this
my postman request is here
I would like to change my GetAllTranslations to accept query parameter instead of path parameter but when I change my postman query to
http://localhost:42677/api/Translate/GetAllTranslations?languageCode=en
I will get error 404 Not found so obviously my controller path is not set correctly, but I cannot find out how to do this... Any Ideas?
I have tried removing the [HttpGet("{languageCode}")] attribute, but I keep getting null parameter instead of the value.
This is what you're looking for
public IActionResult GetAllTranslations([FromQuery]string languageCode)
The answer from #jcmontx worked, but it doesn't explain why parameter bindind needs to be explicitly set. I am still not sure if and why is this enforced,
but one reason would be that if binding parameters are not set explicitly, it opens up the API to be used the way it was not intended, which is not very secure neither a good practice.