How do I reflect a dotnet web api endpoint that uses query string parameters in SwagggerUI? - asp.net-core

I'm trying to implement a dotnet web api with API versioning that uses query strings and headers. Here im using swagger to document and test the endpoints. I successfully used path versioning and reflected the endpoints in swagger. But im struggling to understand how to reflect query string & header versioning in swagger. I tried to find a solution from this article https://swagger.io/docs/specification/describing-parameters/#query-parameters but was still confused how to implement this in my dotnet web api.
My project contains 2 main controller classes with the following API versions.
WeatherForecastController.cs
namespace QueryStringVersioning.Controllers
{
[ApiController]
[ApiVersion("1.0")]
[ApiVersion("1.1", Deprecated = true)]
[ApiVersion("3.0")]
[Route ("api")] //support query string & header versioning
// [Route("api/v{version:apiVersion}/[controller]")] //support path versioning
public class WeatherForecastController : ControllerBase
{
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering",
"Scorching"
};
private readonly ILogger<WeatherForecastController> _logger;
public WeatherForecastController(ILogger<WeatherForecastController> logger)
{
_logger = logger;
}
[HttpGet]
public IEnumerable<WeatherForecast> Get()
{
var rng = new Random();
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = rng.Next(-20, 55),
Summary = Summaries[rng.Next(Summaries.Length)]
})
.ToArray();
}
[HttpGet, MapToApiVersion("3.0")]
public IActionResult GetV3_0() => Ok(new string[] { "MapToApiVersion value 3.0" });
[HttpGet, MapToApiVersion("1.1")]
public IActionResult GetV1_1() => Ok(new string[] { "Depreceated MapToApiVersion value" });
}}
WeatherForecastController2.cs
namespace QueryStringVersioning.Controllers2
{
[ApiController]
[ApiVersion("2.0")]
[ApiVersion("2.1")]
[Route ("api")] //support query string & header versioning
// [Route("api/v{version:apiVersion}/[controller]")] //support path versioning
public class WeatherForecastController : ControllerBase
{
public IActionResult GetV2_0() => Ok(new string[] { "This is API Version 2.0" });
[HttpGet, MapToApiVersion("2.1")]
public IActionResult GetV2_1() => Ok(new string[] { "This is API Version 2.1" });
}}
And the startup.cs file
namespace QueryStringVersioning
{
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.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new Microsoft.OpenApi.Models.OpenApiInfo
{
Version = "v1",
Title = "API_Versioning V1",
});
c.SwaggerDoc("v1.1", new Microsoft.OpenApi.Models.OpenApiInfo
{
Version = "v1.1",
Title = "API_Versioning V1.1",
});
c.SwaggerDoc("v2", new Microsoft.OpenApi.Models.OpenApiInfo
{
Version = "v2",
Title = "API_Versioning V2"
});
c.SwaggerDoc("v2.1", new Microsoft.OpenApi.Models.OpenApiInfo
{
Version = "v2.1",
Title = "API_Versioning V2.1"
});
c.SwaggerDoc("v3", new Microsoft.OpenApi.Models.OpenApiInfo
{
Version = "v3",
Title = "API_Versioning V3"
});
c.ResolveConflictingActions (apiDescriptions => apiDescriptions.First ());
// c.OperationFilter<RemoveVersionFromParameter>();
// c.DocumentFilter<ReplaceVersionWithExactValueInPath>();
});
services.AddControllers();
services.AddMvc();
services.AddApiVersioning(option =>
{
option.ReportApiVersions = true;
option.AssumeDefaultVersionWhenUnspecified = true;
option.DefaultApiVersion = new ApiVersion(1, 0);
// Supporting multiple versioning scheme
option.ApiVersionReader = ApiVersionReader.Combine(new HeaderApiVersionReader("X-version"), new QueryStringApiVersionReader("api-version"));
});
}
// 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.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
// 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", "API_Versioning V1.0");
c.SwaggerEndpoint("/swagger/v1.1/swagger.json", "API_Versioning V1.1");
c.SwaggerEndpoint("/swagger/v2/swagger.json", "API_Versioning V2.0");
c.SwaggerEndpoint("/swagger/v2.1/swagger.json", "API_Versioning V2.1");
c.SwaggerEndpoint("/swagger/v3/swagger.json", "API_Versioning V3.0");
});
}
}
}

#michael-wang is correct. You need to also include the API Versioning API Explorer extensions. This extensions make API discovery API version aware. One of the many possible uses for this information is OpenAPI/Swagger integration.
Links to all of the applicable NuGet packages are listed on the API Versioning landing page. There is also an end-to-end example provided using Swashbuckle.

Related

Swashbuckle extension version switch

I am new to asp.net core and I am using swagger. I downloaded it by following the steps Install-Package Swashbuckle.AspNetCore -Version 5.6.3.Then add middleware
services.AddSwaggerGen();Then add app.UseSwagger(c =>
{
c.SerializeAsV2 = true;
});
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
}); to the ge
nerated JSON document and Swagger UI.
Finally add the header information as per the documentation.
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo
{
Version = "v1",
Title = "ToDo API",
Description = "A simple example ASP.NET Core Web API",
TermsOfService = new Uri("https://example.com/terms"),
Contact = new OpenApiContact
{
Name = "Shayne Boyer",
Email = string.Empty,
Url = new Uri("https://twitter.com/spboyer"),
},
License = new OpenApiLicense
{
Name = "Use under LICX",
Url = new Uri("https://example.com/license"),
}
});
});
These are all requirements to follow the documentation. But I need to extend the requirements now, I need to add the version information of the API, similar to the API V1 API V2 version switch. I have referenced some sources but don't have the complete code, can you guys help me? Any help is excellent! !
Are you trying to switch versions like this?
First I created 2 versions of folders and controllers.Therefore, the namespace of each controller corresponds to its folder, like this:
V1 version:
namespace WebApplication129.Controllers.V1
{
[ApiController]
[Route("api/v1/[controller]")]
public class HomeController : ControllerBase
{
[Route("test")]
[HttpGet]
public string Test()
{
return "v1 test";
}
}
}
V2 version:
namespace WebApplication129.Controllers.V2
{
[ApiController]
[Route("api/v2/[controller]")]
public class HomeController : ControllerBase
{
[Route("test")]
[HttpGet]
public string Test()
{
return "v2 test";
}
}
}
Then create an agreement to inform Swagger, in this way, we can control how Swagger generates Swagger documents, thereby controlling the UI.
Create the following class:
public class GroupingByNamespaceConvention : IControllerModelConvention
{
public void Apply(ControllerModel controller)
{
var controllerNamespace = controller.ControllerType.Namespace;
var apiVersion = controllerNamespace.Split(".").Last().ToLower();
if (!apiVersion.StartsWith("v")) { apiVersion = "v1"; }
controller.ApiExplorer.GroupName = apiVersion;
}
}
Now we must apply the convention. For that we go to AddControllers in ConfigureServices and add the convention:
services.AddControllers(options =>
{
options.Conventions.Add(new GroupingByNamespaceConvention());
});
The final complete startup.cs configuration is as follows:
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.OpenApi.Models;
using System;
using WebApplication129.Controllers.conf;
namespace WebApplication129
{
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.AddControllers(options =>
{
options.Conventions.Add(new GroupingByNamespaceConvention());
});
services.AddSwaggerGen(config =>
{
var titleBase = "Test API";
var description = "This is a Web API for Test operations";
var TermsOfService = new Uri("https://xxxxxx");
var License = new OpenApiLicense()
{
Name = "Test"
};
var Contact = new OpenApiContact()
{
Name = "Test",
Email = "Test#hotmail.com",
Url = new Uri("https://xxxxxx")
};
config.SwaggerDoc("v1", new OpenApiInfo
{
Version = "v1",
Title = titleBase + " v1",
Description = description,
TermsOfService = TermsOfService,
License = License,
Contact = Contact
});
config.SwaggerDoc("v2", new OpenApiInfo
{
Version = "v2",
Title = titleBase + " v2",
Description = description,
TermsOfService = TermsOfService,
License = License,
Contact = Contact
});
});
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseSwagger();
app.UseSwaggerUI(config =>
{
config.SwaggerEndpoint("/swagger/v1/swagger.json", "API v1");
config.SwaggerEndpoint("/swagger/v2/swagger.json", "API v2");
});
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
}

URL Globalization in asp.net core 5

I am about to change my asp.net core Globalization by URL.
Just like Microsoft official site:
https://www.microsoft.com/zh-cn/ is for the Chinese version.
https://www.microsoft.com/en-us/ is for the English version.
What I want to do is something different:
https://www.aaa.com/zh-hans/index.html is for the Chinese version.
https://www.aaa.com/en/index.html is for the English version.
As you see above, I need to add a .html suffix also.
I found some tutorials on google.
Here is my code:
public void ConfigureServices(IServiceCollection services)
{
services.AddLocalization(options => options.ResourcesPath = "Resources");
services.AddMvc().AddViewLocalization(Microsoft.AspNetCore.Mvc.Razor.LanguageViewLocationExpanderFormat.Suffix,
options => options.ResourcesPath = "Resources").AddSessionStateTempDataProvider();
}
public void Configure(IApplicationBuilder app)
{
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.UseRouting();
app.UseStaticFiles();
var SupportedCultures = new List<CultureInfo> {
new CultureInfo("en"),
new CultureInfo("zh-Hans"),
new CultureInfo("zh-Hant")
};
var options = new RequestLocalizationOptions
{
DefaultRequestCulture = new RequestCulture("en"),
SupportedCultures = SupportedCultures,
SupportedUICultures = SupportedCultures,
};
app.UseRequestLocalization(options);
var requestProvider = new RouteDataRequestCultureProvider();
options.RequestCultureProviders.Insert(0, requestProvider);
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(name: "default", pattern: "{culture}/{controller=Home}/{action=Index}.html", defaults: new { culture = "en", controller = "Home", action = "Index" });
});
}
However, after the website ran, it reports an error:
An unhandled exception occurred while processing the request.
AmbiguousMatchException: The request matched multiple endpoints. Matches:
Sample.Controllers.HomeController.Index (Sample)
Sample.Controllers.HomeController.Error (Sample)
Sample.Controllers.HomeController.Privacy (Sample)
Microsoft.AspNetCore.Routing.Matching.DefaultEndpointSelector.ReportAmbiguity(CandidateState[] candidateState)
It seems that's because I added a .html suffix in MapControllerRoute.
I am not quite sure whether my code is right for most of the tutorial is for asp.net core 2 or even for asp.net core 1. Most of the code now not work in asp.net core 5 anymore.
What's wrong with my code? Thank you.
HomeController:
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using Sample.Models;
namespace Sample.Controllers
{
public class HomeController : Controller
{
private readonly ILogger<HomeController> _logger;
public HomeController(ILogger<HomeController> logger)
{
_logger = logger;
}
public IActionResult Index()
{
return View();
}
public IActionResult Privacy()
{
return View();
}
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public IActionResult Error()
{
return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
}
}
}

Localization in .NET Core API

I am trying to create localization Middleware in .NET Core API 2.2, I was following Microsoft's official instruction but I don't quite understand, how it works? I don't have views, so I must localize models with data annotations right?
I want to get language values through Accept-Language HTTP Header
here is my Middleware:
public void ConfigureServices(IServiceCollection services)
{
services.AddLocalization(options => options.ResourcesPath = "Resources");
services.AddMvc()
.AddDataAnnotationsLocalization();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
var supportedCultures = new[] { "en-US", "ka-Ge" };
var localizationOptions = new RequestLocalizationOptions().SetDefaultCulture(supportedCultures[0])
.AddSupportedCultures(supportedCultures)
.AddSupportedUICultures(supportedCultures);
app.UseRequestLocalization(localizationOptions);
}
Model:
public class PersonsModel
{
[Display(Name = "Name")]
public string Name { get; set; }
}
I have Resx Files in Resourses folders: PersonsController.en-Us
please edit/improve/correct/adjust
references:
https://damienbod.com/2015/10/21/asp-net-5-mvc-6-localization/
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/localization?view=aspnetcore-3.1#implement-a-strategy-to-select-the-languageculture-for-each-request
https://ml-software.ch/posts/writing-a-custom-request-culture-provider-in-asp-net-core-2-1
ASP.NET Core Request Localization Options
No, you need to apply somewhere (in your LocalizationMiddleware) IStringLocalizer, so you can create a getFunction with LocalizedString as return type.
That way you can use localization in your application wherever you want it.
Based on the culture-information of your current thread, and how you have defined your SharedResource, you'll get the corresponding value for the key.
You can find a solution below:
Checklist
Configure services in the DI container
a. Register the service in
the Startup-method (see created separate classDIConfiguration)
b. Configure and apply options of Localization in the
Configure-method
Define Localizationoptions (CustomRequestCultureProvider Class)
Build up your middleware in the appropriate project (business logic)
Define SharedResource.class and resx-files in the same project
Inject Middleware in business logic-class (handler)
 
Configure services in the DI container
a. Register the service in the Startup-method (see created separate classDIConfiguration)
b. Configure and apply options of Localization in the Configure-method
using …
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.SpaServices.AngularCli;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
readonly string MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();services.AddCors(options =>
{
options.AddPolicy(name: MyAllowSpecificOrigins,
builder =>
{
builder.WithOrigins("http://localhost:4200")
.AllowAnyHeader()
.AllowAnyMethod()
.WithExposedHeaders("Content-Disposition");
});
});
// In production, the Angular files will be served from this directory
services.AddSpaStaticFiles(configuration =>
{
configuration.RootPath = "ClientApp/dist";
});
DiConfiguration.ConfigureServices(Configuration, services);
AutoMapperConfiguration.ConfigureAutoMapper(services);
services.AddMediatorAndBehaviour();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
var supportedCultures = new[] { "nl", "en", "fr", "de" };
var localizationOptions = new RequestLocalizationOptions()
.SetDefaultCulture(supportedCultures[0])
.AddSupportedCultures(supportedCultures)
.AddSupportedUICultures(supportedCultures);
localizationOptions.RequestCultureProviders.Clear();
localizationOptions.RequestCultureProviders.Add(new CustomRequestCultureProvider(localizationOptions));
app.UseRequestLocalization(localizationOptions);
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
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();
if (!env.IsDevelopment())
{
app.UseSpaStaticFiles();
}
app.UseAuthentication();
app.UseRouting();
app.UseAuthorization();
app.UseCors(MyAllowSpecificOrigins);
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller}/{action=Index}/{id?}");
});
app.UseSpa(spa =>
{
// To learn more about options for serving an Angular SPA from ASP.NET Core,
// see https://go.microsoft.com/fwlink/?linkid=864501
spa.Options.SourcePath = "ClientApp";
if (env.IsDevelopment())
{
spa.UseAngularCliServer(npmScript: "start");
}
});
app.UseHttpsRedirection();
}
}
 
using System;
using System.Text;
…
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Tokens;
public static class DiConfiguration
{
public static void ConfigureServices(IConfiguration configuration, IServiceCollection services)
{
// Configure Database services
services.AddDbContextPool<IsisContext>(options => options.UseSqlServer(configuration.GetConnectionString("IsisDatabase")));
services.AddScoped<IIsisUnitOfWork, IsisUnitOfWork>();
…
services.AddSingleton<ILocalizationMiddleware, LocalizationMiddleware>();
services.AddControllers();
services.AddMemoryCache();
services.AddOptions();
…
services.AddLocalization(options => options.ResourcesPath = "Resources");
}
}
Define Localizationoptions (CustomRequestCultureProvider Class)
using …;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Localization;
using System;
using System.Linq;
using System.Threading.Tasks;
public class CustomRequestCultureProvider : IRequestCultureProvider
{
public CustomRequestCultureProvider(RequestLocalizationOptions options)
{
}
public Task<ProviderCultureResult> DetermineProviderCultureResult(HttpContext httpContext)
{
try
{
var transmittedLanguageCode = httpContext.Request.GetTypedHeaders().AcceptLanguage;
string transmittedLanguageCodeString = transmittedLanguageCode.LastOrDefault().ToString();
return Task.FromResult(new ProviderCultureResult(transmittedLanguageCodeString));
}
catch (Exception)
{
return Task.FromResult(new ProviderCultureResult(LanguagesDefinition.NL)); // scenario NL is the default
}
}
}
 
3. Build up your middleware in the appropriate project (business logic)
using Microsoft.Extensions.Localization;
namespace ….Business.LocalizationService
{
public interface ILocalizationMiddleware
{
public LocalizedString GetLocalizedString(string keyForResourceTable);
}
}
using Microsoft.Extensions.Localization;
using System.Reflection;
namespace ….Business.LocalizationService
{
public class LocalizationMiddleware : ILocalizationMiddleware
{
private readonly IStringLocalizer localizer;
public LocalizationMiddleware(IStringLocalizerFactory factory)
{
localizer = factory.Create("SharedResource", Assembly.GetExecutingAssembly().FullName);
}
public LocalizedString GetLocalizedString(string keyForResourceTable) { return localizer[keyForResourceTable]; }
}
}
 
4; Define (SharedResource.class optional) Resources-folder and resx-files in the same project
 
5. Inject Middleware in business logic-class (handler)
public class SomeClass
{
public AdvancedSearchResultDtoToCsvMap(ILocalizationMiddleware localizationMiddleware)
{
Map(m => m.Id).Ignore();
Map(m => m.ArticleCode).Index(0).Name(localizationMiddleware.GetLocalizedString("articlecode").Value);
Map(m => m.Fullname).Index(1).Name(localizationMiddleware.GetLocalizedString("fullname").Value);
…
}
}

Can't get Odata 7.1 working in web api (.net core 2.2)

I'm having trouble implementing OData in my Web API project.
I'm using .NET Core 2.2 and OData (Microsoft.AspNetCore.OData v7.1.0).
(I also have AutoMapper installed, but I don't think this is relevant)
The problem is that the response is never enriched with the extra properties (like odata.context and odata.count). Also, adding ?count=true doesn't do anything either.
Does anyone have any idea why this is happening?
This is my Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
/* AutoMapper config */
var mappingConfig = new MapperConfiguration(mc =>
{
mc.AddProfile(new MappingProfile());
});
IMapper mapper = mappingConfig.CreateMapper();
services.AddSingleton(mapper);
services.AddMvc(opt => opt.EnableEndpointRouting = false).SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
services.AddOData();
var connection = #"snipped-connection-string";
services.AddDbContext<AllOnBoardContext>
(options => options.UseSqlServer(connection));
/* CORS for local development, not ideal, I know */
services.AddCors(setup =>
{
setup.AddPolicy(AllowCorsPolicyName, builder =>
{
builder.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod();
});
});
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
// 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.UseCors(AllowCorsPolicyName);
app.UseMvc(routeBuilder =>
{
routeBuilder.Select().Filter().OrderBy().Expand().Count().MaxTop(10);
routeBuilder.MapODataServiceRoute("api", "api", GetEdmModel());
});
}
private static IEdmModel GetEdmModel()
{
ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
builder.EntitySet<Tenant>("Tenants");
return builder.GetEdmModel();
}
And this is my `Controller´ class:
public class TenantController : ControllerBase
{
private ITenantService tenantService;
public TenantController(ITenantService tenantService, IMapper mapper) : base(mapper, tenantService)
{
this.tenantService = tenantService;
}
[HttpGet]
[EnableQuery()]
public ActionResult<IEnumerable<TDto>> Get()
{
return Service.GetAll().ToList();
}
}
First of all, OData query parameters always start with a $. So in your case, it is ?$count=true.
Next, make sure that every Controller inherits from ODataController:
[ODataRoutePrefix("Tenants")]
public class TenantController : ODataController
{
private ITenantService tenantService;
public TenantController(ITenantService tenantService, IMapper mapper) : base(mapper, tenantService)
{
this.tenantService = tenantService;
}
[HttpGet]
[ODataRoute]
[EnableQuery]
public ActionResult<IEnumerable<TDto>> Get()
{
return Service.GetAll().ToList();
}
}
Annotations will help you to control OData. The prefix string of the ODataRoutePrefixAttribute specifies the OData URL path template that this action handles (in your case http://<host:port>/api/Tenants) and with the ODataRouteAttribute it is possible to specify the OData URL path template that this action handles.

How can I test API calls in postman in the .net core 2.1 Angular template?

I can't seem to connect to any of my controller methods in Postman. It does work in the angular app. The project is generated as the doc suggets here
This controller method comes with the template:
[Route("api/[controller]")]
public class SampleDataController : Controller
{
private static string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
[HttpGet("[action]")]
public IEnumerable<WeatherForecast> WeatherForecasts()
{
var rng = new Random();
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
DateFormatted = DateTime.Now.AddDays(index).ToString("d"),
TemperatureC = rng.Next(-20, 55),
Summary = Summaries[rng.Next(Summaries.Length)]
});
}
public class WeatherForecast
{
public string DateFormatted { get; set; }
public int TemperatureC { get; set; }
public string Summary { get; set; }
public int TemperatureF
{
get
{
return 32 + (int)(TemperatureC / 0.5556);
}
}
}
}
In my Startup.cs I have configured the routes as follows:
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller}/{action=Index}/{id?}");
});
app.UseSpa(spa =>
{
// To learn more about options for serving an Angular SPA from ASP.NET Core,
// see https://go.microsoft.com/fwlink/?linkid=864501
spa.Options.SourcePath = "ClientApp";
if (env.IsDevelopment())
{
//delay timeout 2 min to avoid timeout
spa.Options.StartupTimeout = new TimeSpan(0, 5, 0);
spa.UseAngularCliServer(npmScript: "start");
}
});
When I run the application and try to make a get request in Postman I get no response. I'm calling:
https://localhost:44389/api/sampledata/weatherforecasts
I figured it may be a port problem but this is the port the application runs on but I could be missing something
Any ideas?
I had the same problem.
In Startup.cs let's comment or delete this line.
app.UseHttpsRedirection();
Then Postman acts as expected.
I had the same problem with .Net Core 3.1 Angular template, but it is worked to me if I remove api from url.
Eg: https://localhost:44389/sampledata/weatherforecasts