Disable ApiVersioning for OData controllers - asp.net-core

is there any way to disable ApiVersioning only for OData controllers?
I have an application in which there are REST controllers and OData controllers. The problem occurs when I add AddApiVersioning. REST Controllers work as they should. OData controllers returns HTTP ERROR 404.
If I remove AddApiVersioning then OData controllers work properly.
The application is running on ASP.NET Core 3.1
public void ConfigureServices(IServiceCollection serviceCollection)
{
...
serviceCollection.AddOData();
serviceCollection.AddApiVersioning(options =>
{
options.ReportApiVersions = true;
options.AssumeDefaultVersionWhenUnspecified = true;
});
...
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILogger<Startup> logger)
{
...
app.UseEndpoints(endpoints =>
{
...
endpoints.EnableDependencyInjection();
endpoints.MapODataRoute("odata", "/odata", ODataConfiguration.GetEdmModel());
...
});
...
}
Thank you for answer.

Related

OData integration with CosmosDb does not return expected result

I have created a .NET Core 3.1 WebAPI application which connect with Azure Cosmos Db. The WebAPI is returning data from CosmosDb correctly. When I tried to integrate OData to this solution, and tried to query data using the Select method, it does not return expected result.
The following are my code:
StartUp.cs
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.AddOData();
services.AddControllersWithViews();
services.AddSingleton<ICosmosDbService>(InitializeCosmosClientInstanceAsync(Configuration.GetSection("CosmosDb")).GetAwaiter().GetResult());
}
// 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();
}
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.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=ToDo}/{action=Index}/{id?}");
endpoints.EnableDependencyInjection();
endpoints.Select().Filter().OrderBy().Expand();
});
}
}
WebAPI controller:
[Produces("application/json")]
[Route("api/[controller]")]
[ApiController]
public class ItemsController : ControllerBase
{
private readonly ICosmosDbService _cosmosDbService;
public ItemsController(ICosmosDbService cosmosDbService)
{
_cosmosDbService = cosmosDbService;
}
// GET: api/<ItemsController>
[HttpGet]
[EnableQuery()]
public async Task<IEnumerable<Item>> Get()
{
return await _cosmosDbService.GetItemsAsync("SELECT * FROM c");
}
}
When I try to retrieve data using the API call(https://localhost:44357/api/items), I am getting expected result:
[{"id":"5f4f5d02-9217-4591-8f8c-2af9fe7d9ae4","name":"Brush","description":"Brush your teeth every night","completed":true,"partitionKey":null},{"id":"6a5edfe3-9c84-4398-bed4-963dbb4a42e3","name":"Excercise","description":"Hit the gym in the evening","completed":true,"partitionKey":null}]
But when I try to use the OData method(https://localhost:44357/api/items?$select=name), I am not getting expected result. Instead, I am getting this:
[{"instance":null,"container":{},"modelID":"7c0ae376-1666-46f8-886f-9bf758824063","untypedInstance":null,"instanceType":null,"useInstanceForProperties":false},{"instance":null,"container":{},"modelID":"7c0ae376-1666-46f8-886f-9bf758824063","untypedInstance":null,"instanceType":null,"useInstanceForenter code hereProperties":false}]
Any idea why it is like this?
There is incompatible situation with the JSON serializer in Asp.Net 3.1. Try to AddNewtonsoftJson.
services.AddControllers(mvcOptions =>
mvcOptions.EnableEndpointRouting = false)
.AddNewtonsoftJson();

Difference between UseRouter and UseEndpoints

I want to handle requests for a particular path in ASP.NET Core without using controllers.
It seems that I have two options now:
Using the app.UseRouter(r => r.MapPost(...)):
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseRouter(r => {
r.MapPost("foo/{fooId:int}/bar", (request, response, routeData) =>
{
// My logic
response.StatusCode = StatusCodes.Status200OK;
return Task.CompletedTask;
});
});
}
Using the app.UseEndpoints(e => e.MapPost(...)):
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapPost("foo/{fooId:int}/bar", context =>
{
// My logic
context.Response.StatusCode = StatusCodes.Status200OK;
return Task.CompletedTask;
});
});
}
Both options seem to behave identically.
What is the principal difference between the two and which one should I use?
As far as I understand:
UseRouter is the old way of routing (defined in .net core 2.1)
UseEndpoints is the new way of routing (defined in .net core 3.0)
UseEndpoints supports metadata, context.GetEndpoint() and other powerful features. So it is the preferred option.
UPDATE: Starting from .net 6 both of these approaches are no longer recommended and are replaced with Minimal API.

How to set default razor page route with asp.net 3.0 middleware

So to setup endpoint routing in asp.net core 3.x, we do something like this
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
//...
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapRazorPages();
});
}
How/where can we define a "default" page route other than index?
The easiest solution would be to manually add route to the custom page in ConfigureServices
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages(o => o.Conventions.AddPageRoute("/CustomPage", ""));
}
With this solution you need to rename or remove Index page to avoid AmbiguousMatchException
This is an example of a default route.
app.UseEndpoints(endpoint =>
{
endpoint.MapDefaultControllerRoute();
});

OData and .NET Core 2 Web API - disable case-sensitivity?

I'm new to OData, and I'm trying to integrate it into our .NET Core 2.0 Web API using the Microsoft.AspNetCore.OData 7.0.0-beta1 NuGet package. I would like my OData URLs to be case-insensitive (i.e., http://localhost:1234/odata/products would be the same as http://localhost:1234/odata/Products). How can I accomplish this? The relevant portion of my Startup code is as follows:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, IApplicationLifetime appLifetime)
{
// ...
var odataBuilder = new ODataConventionModelBuilder(app.ApplicationServices);
odataBuilder.EntitySet<Product>("products");
app.UseMvc(routeBuilder =>
{
routeBuilder.MapODataServiceRoute("ODataRoute", "odata", odataBuilder.GetEdmModel());
// Workaround for https://github.com/OData/WebApi/issues/1175.
routeBuilder.EnableDependencyInjection();
});
// ...
}
I just figured this out myself. You can reference https://github.com/OData/WebApi/issues/812.
The long and short of it is that you need to first add a class like this to your project:
public class CaseInsensitiveResolver : ODataUriResolver
{
private bool _enableCaseInsensitive;
public override bool EnableCaseInsensitive
{
get => true;
set => _enableCaseInsensitive = value;
}
}
And then you must create your service route in a slightly different manner:
routeBuilder.MapODataServiceRoute("ODataRoute", "odata",
b => b.AddService(ServiceLifetime.Singleton, sp => odataBuilder.GetEdmModel())
.AddService<ODataUriResolver>(ServiceLifetime.Singleton, sp => new CaseInsensitiveResolver()));
This fixed my case of the mondays.

Changing ASP Core default route to different controller

I cannnot get my ASP .NET Core MVC site to route to different controller other than Home. I changed the default route in Startup (it is the only route):
app.UseMvc(routes =>
{
routes.MapRoute(name: "default", template: "{controller=profile}/{action=index}/{id?}");
});
my ProfileController looks like:
public class ProfileController : Controller
{
[HttpGet("index")]
public IActionResult Index()
{
return View();
}
...
}
But all I get is 404 returned form the Kestrel server on navigating to base URL.
I've just created a new project and it worked for me. Maybe you're doing something else wrong.
Here's what I did.
Create a new asp.net core web application project (choose MVC template)
Update the default route in the Startup.cs:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) {
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
if (env.IsDevelopment()) {
app.UseDeveloperExceptionPage();
app.UseBrowserLink();
} else {
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
app.UseMvc(routes => {
routes.MapRoute(
name: "default",
template: "{controller=profile}/{action=index}/{id?}");
});
}
Create the Profile Controller:
public class ProfileController : Controller {
// GET: /<controller>/
public IActionResult Index() {
return View();
}
}
Create the Index View for the Profile Controller:
Run the project and the Profile's Index page should open.
UPDATE:
The problem was the [HttpGet("index")] in the Profile Controller.