.NET Core and Swagger API generation - c#

I am creating a barebones .NET Core web api project (Started from blank template below)
https://andrewlock.net/removing-the-mvc-razor-dependencies-from-the-web-api-template-in-asp-net-core/
The code below was working fine, untill I added Swashbuckle.AspNetCore (Along with the configuration code below), now we get this error
InvalidOperationException: No service for type 'Microsoft.AspNetCore.Mvc.ApiExplorer.IApiDescriptionGroupCollectionProvider' has been registered.
Any ideas?
Please note: We are not using "builder.AppMvc()" as we are trying to slim this api down as much as possible.
public class Startup
{
// 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)
{
var builder = services.AddMvcCore();
builder.AddAuthorization();
builder.AddFormatterMappings();
builder.AddJsonFormatters();
builder.AddCors();
// Register the Swagger generator, defining one or more Swagger documents
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new Info { Title = "My API", 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, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole();
if (env.IsDevelopment())
app.UseDeveloperExceptionPage();
app.UseMvc();
// 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");
});
}
}
[Route("api/[controller]")]
public class ValuesController : ControllerBase
{
// GET api/values
[HttpGet]
public IActionResult Get()
{
return Ok(new[] {"value1", "value2"});
}
}

Solution: Use AddMvc() instead of AddMvcCore() in Startup.cs and it will work.
or write:
services.AddMvcCore().AddApiExplorer();
These links can help:
No service for type 'Microsoft.AspNetCore.Mvc.ViewFeatures.ITempDataDictionaryFactory' has been registered
https://github.com/domaindrivendev/Swashbuckle.AspNetCore/issues/299

For ASP.NET Core 2.2 you should write:
services.AddMvcCore().AddApiExplorer();

These types of errors also appear if you try to add AspNetCore MVC controller with Swagger UI into the AspNetCore Web Application. Just separate them into two different projects: mvc controllers and web application.

Related

What is the difference between services.Add and app.Use in startup class in ASP.NET Core?

I begin to learn ASP.NET Core, there, within the framework of the Web API template, there is a Startup class with ConfigureServices() and Configure() methods.
Can anyone tell me about how to use them? I am watching an Udemy course and I didn't understand why the instructor doing
public class Startup
{
private readonly IConfiguration config;
public Startup(IConfiguration config)
{
this.config = config;
}
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.AddApplicationServices(this.config);
services.AddControllers();
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "WebAPIv5", Version = "v1" });
});
services.AddCors();
services.AddIdentityServices(this.config);
}
// 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.UseSwagger();
// app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "WebAPIv5 v1"));
//}
app.UseMiddleware<ExceptionMiddleware>();
app.UseHttpsRedirection();
app.UseRouting();
app.UseCors(x => x
.AllowAnyMethod()
.AllowAnyHeader()
.SetIsOriginAllowed(origin => true) // allow any origin
.AllowCredentials());
services.Add is to register service , app.Use is the way to use Middleware
Configure Service(): It is used to add services to the container and configure those services. basically, service is a component that is intended for common consumption in the application. There is framework service like MVC, EF core, identity so on. but there are also application services that are application-specific like send mail services.
Configure(): it is used to specify how the asp.net core application will respond to individual requests. Through this, we actually build the HTTP request pipeline
public class Startup {
// This method gets called by the runtime.
// Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services) {
// Register services here through dependency injection
}
// This method gets called by the runtime.
// Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app,
IWebHostEnvironment env) {
// Add middlware components here
if (env.IsDevelopment()) {
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseEndpoints(endpoints => {
endpoints.MapGet("/",async Context => {
await context.Response.WriteAsync("Hello World!");
});
});
}
}
Read this example to know more.
Configure.Services and Configure are the starting points from where you can configure framework-level settings in ASP.NET Core.
Configure.Services: To add all the services i.e. the types that you created to add business, database logic to your API. e.g.: You might have created your own logging service and you need to inject in the other classes through DI. To create the objects for these Logging service you need to first register it in the IOC containter of the ASP.NET Core and Configure.Services is the place where you add those services.
Configure: To configure the request-response pipeline i.e. the types that handles the incoming request and outgoing response. e.g.: You might want to add some kind of authentication and authorization before request reaches your controller. Configure is the place where you add those middlewares.

Access JsonOptions from a middleware in ASP.NET Web Api

In a ASP.NET Web API project I have a custom json converter. It works perfectly fine in a scenario with a typical API controller methods. But somehow I can not access the configured JsonOptions from a middleware which works outside the standard Web API pipeline.
A simple middleware to reproduce the problem:
public sealed class TestMiddleware
{
public async Task Invoke(HttpContext httpContext, IOptions<JsonOptions> jsonOptions)
{
// Some logic to check the middleware must be applied
// ...
// Return a response
await httpContext.Response.WriteAsJsonAsync(data, jsonOptions.Value.SerializerOptions);
}
}
And the configuration fragment:
public void ConfigureServices(IServiceCollection services)
{
services
.AddControllers()
.AddJsonOptions(configure =>
{
configure.JsonSerializerOptions.Converters.Add(new MyCustomConverter());
configure.JsonSerializerOptions.IgnoreNullValues = true;
});
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseHttpsRedirection();
app.UseMiddleware<TestMiddlewre>();
app.UseRouting();
app.UseEndpoints(endpoints => { endpoints.MapControllers(); });
}
When a http request hits the middleware IOptions<JsonOptions> jsonOptions has a SerializerOptions object which doesn't contain converters that I have setup in the configuration.
Is there a way to access the actual JsonOptions with the proper configured SerializerOptions?
The problem was quite tricky. There are two namespaces containing a JsonOptions class:
Microsoft.AspNetCore.Mvc
Microsoft.AspNetCore.Http.Json
Using the first one resolved my problem. Internally these two classes are very similar and I didn't pay attention for the corresponding namespace during the middleware implementation.

Change MVC Home Landing Page: No service for type 'Microsoft.Extensions.DependencyInjection.IServiceCollection' has been registered

I tried changing the landing page of my web page mvc application using this command.
I received this error below. How would I resolve it?
public void Configure(IServiceCollection services, IApplicationBuilder app, IHostingEnvironment env)
{
app.AddMvc().AddRazorPagesOptions(options =>
{
options.Conventions.AddPageRoute("/Products/Index", "");
});
Error:
InvalidOperationException: No service for type 'Microsoft.Extensions.DependencyInjection.IServiceCollection' has been registered.
Add a ConfigureServices method in order to configure services and DI:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().AddRazorPagesOptions(options =>
{
options.Conventions.AddPageRoute("/Products/Index", "");
});
}
The Configure method should be used to configure the HTTP pipeline (i.e. app.UseMvc();)
For further read, see App startup in ASP.NET Core

Getting Access-Control-Allow-Origin error even tho i added app.useCors (Angular, c# .net core API)

Still getting Access-Control-Allow-Origin error even tho i added useCors in my startup class. I am also using angular 5. I used to get this error when I ran my project but i fixed it by adding cors in my startup, but now i am getting it when i try to call post api method from my angular project.
my startup.cs code:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddCors();
services.AddMvc();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseCors(builder => builder
.AllowAnyOrigin()
.AllowAnyHeader()
.AllowAnyMethod()
.AllowCredentials());
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseMvc();
}
}
You can use proxy in your client and change client's origin to whatever you want.
The advantages of this solution are :
You don't need to define CORS in you'r back-end ( increase security )
You don't need to be worry about your client as well as you just run your project via npm start, as soon as you want to release your application you can run ng build command and proxy will be ignored from your setting.
For using proxy
edit "start" of your package.json to look below
"start": "ng serve --proxy-config proxy.conf.json",
create a new file called proxy.conf.json in the root of the project and inside of that define your proxies like below
{
"/api/*": {
"target": "http://localhost:56492",
"secure": "false"
}
}
Important thing is that you use npm start instead of ng serve
Now in you'r service.ts , post/get requests url instead of localhost:56492/... just type /api/Film.
Read more from here : Proxy Setup angular 2 cli

Using Azure Active Directory authentication in ASP.NET Core 2.0 from Web App to Web API

I am trying to pass Azure Active Directory credentials from an ASP.NET Core 2.0 Web App to an ASP.NET Core 2.0 Web API so that the Web API can react based on the user's properties and permissions.
There are, admittedly, quite a few tutorials out there about these technologies in various scenarios and combinations, but I've been having trouble finding clear help specifically for Core 2.0 due to how recently it was released, and I'm avoiding getting too invested in any of the Core 1.x tutorials because it seems there have been some breaking changes when it comes to this (JWT, authentication, etc.). I'm entirely new to Core, so I can't tell what's what.
My goal is to ascertain how this is supposed to be done according to Microsoft's suggestions/standards (if they exist). I want to minimize complexity and make use of the tools that have been designed for this ecosystem.
I have registered both the Web App and the Web API in my Azure Active Directory. When I debug my Web App, I am required to log in via my work/school account with Microsoft, and that is working as expected.
This is all unmodified from what was created as a result of my using the templates/wizards to get started, but for reference:
In the Web App:
Startup.cs
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
// (other unrelated stuff)
app.UseAuthentication();
// (other unrelated stuff)
}
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(sharedOptions =>
{
sharedOptions.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
sharedOptions.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddAzureAd(options => Configuration.Bind("AzureAd", options))
.AddCookie();
services.AddMvc();
}
}
Controllers/HomeController.cs
[Authorize]
public class HomeController : Controller
{
public IActionResult Index()
{
// ****************************************************************
// let's imagine I wanted to call the Web API right here, passing authentication
// and whatnot... what should that look like according to this framework?
// ****************************************************************
return View();
}
// (other unrelated actions)
}
In the Web API:
Startup.cs
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
// (other unrelated stuff)
app.UseAuthentication();
app.UseMvc();
}
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(sharedOptions =>
{
sharedOptions.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddAzureAdBearer(options => Configuration.Bind("AzureAd", options));
services.AddMvc();
}
}
I can't think of how many queries I threw into Google until finally trying "c# asp core get access token" and getting this very helpful blog as result #3:
https://blogs.msdn.microsoft.com/gianlucb/2017/10/04/access-an-azure-ad-secured-api-with-asp-net-core-2-0/

Categories