I have a small ASP.NET Core web app project named "OdeToFood". The dev environment includes:
IDE: Visual Studio 2019 on Windows 10 PC
ASP.NET Core 3.1
Use Dapper for data access from SQL DB
Not using MVC
In one of web pages, the jQuery .ajax will be used retrive a record from DB. I added an ApiController with type of "API controller with read/write actions" because the EF is not used in this project.
Here is the code auto generated by VS (no change was made).
namespace OdeToFood.Api
{
[Route("api/[controller]")]
[ApiController]
public class RestaurantsController : ControllerBase
{
// GET: api/<RestaurantsController>
[HttpGet]
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
// GET api/<RestaurantsController>/5
[HttpGet("{id}")]
public string Get(int id)
{
return "value";
}
// POST api/<RestaurantsController>
[HttpPost]
public void Post([FromBody] string value)
{
}
// PUT api/<RestaurantsController>/5
[HttpPut("{id}")]
public void Put(int id, [FromBody] string value)
{
}
// DELETE api/<RestaurantsController>/5
[HttpDelete("{id}")]
public void Delete(int id)
{
}
}
}
I tried to test it from the brower with following URLs:
https://localhost:44361/api/Restaurants
https://localhost:44361/api/Restaurants/8
https://localhost:44361/api/RestaurantsController
https://localhost:44361/api/RestaurantsController/8
They all failed with HTTP 404 error.
Since above code is already using the "Attribute Routing' with [Route ...], I think the first 2 URLs int test should work. But they didn't. I could not figure out why. Any help or suggestion will be greatly appreciated.
In the startup.cs file, the configure section has following settings:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
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();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
});
}
Try below in your startup.cs
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
Comment below;
endpoints.MapRazorPages();
Your Scenario:
Though the solution is very straight forward, I felt more explanation
for you to get rid of any further confustions.
As you said "Visual Studio 2019" so if you have taken asp.net core web api project, it would be created with weather forecast api controller with default startup.cs like below:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
So if you directly run the project it should run with the default action like below:
[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();
}
So now come to your projects configuration which is containing like
below:
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
});
Means its looking for simple mvc razor page and when you are trying
to hit either of this URLs 1. https://localhost:44361/api/Restaurants or 2.https://localhost:44361/api/Restaurants/8 it should get 404 because it's not routed accordingly. So your routing template is not correct to route api controller directly. endpoints.MapRazorPages() is usually used for Razor mvc page routing.
Solution:
If you could add the API controller while you were taking your RestaurantsController I think it would be look like what you posted.
and request should route as expected if you replace the below service
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
Note: You even can override your route template if you want. You could have a look here also if you want which a
conventional route.
Output:
What I tried show you is what mislead you and sharpen your idea. If you have any further query you have a look our official document here. Hope it would help you accordingly.
Related
when I create an admin folder and then add an empty razor page and do /admin, it tells me the page cannot be found. However I have another User folder and when I do /User it works.
These folders are listed in a Views folder.
I tried duplicating the User folder and renaming it to Admin but it didn't work.
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.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(options =>
{
options.LoginPath = "/Admin";
});
//services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddDbContext<ApplicationDbContext>(options=>options.UseSqlServer(Configuration.GetConnectionString("DefaultConnectionSqlite")));
services.AddIdentity<IdentityUser, IdentityRole>().AddEntityFrameworkStores<ApplicationDbContext>().AddDefaultTokenProviders();
services.AddTransient<IEmailSender, MailJetEmailSender>();
services.AddControllersWithViews();
}
// 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.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
}
}
If you have a view named Index.cshtml in the path Views\Admin\Index.cshtml then you should create a Controller named AdminController:
public class AdminController : Controller
{
public IActionResult Index()
{
return View();
}
}
Notice the method name (Index) is the same as the view name.
If you want to have different method name and view name then you need to specify the view name when you return the view:
public class AdminController : Controller
{
public IActionResult View()
{
return View("Index");
}
}
https://learn.microsoft.com/en-us/aspnet/core/tutorials/first-mvc-app/adding-controller?view=aspnetcore-6.0&tabs=visual-studio
I want to add constraints to routing.I am using conventional routing. Following is my code
Startup.cs
using Lab4MVC.Routing;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllersWithViews();
//builder.Services.AddMvc(x => x.EnableEndpointRouting = false);
builder.Services.AddRazorPages();
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.UseMvc();
//app.UseMvcWithDefaultRoute();
//app.UseMvc(routes => {
// Routing.LoadRoutes(routes);
//});
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
Routing.LoadRoutes(endpoints)
);
app.Run();
Routing.cs
using Microsoft.AspNetCore.Builder;
namespace Lab4MVC.Routing
{
public static class Routing
{
public static void LoadRoutes(IEndpointRouteBuilder routeBuilder)
{
routeBuilder.MapControllerRoute(name:"Route1",pattern: "/Customer/Add/{Id}",defaults: new
{
contoller = "Customer",
action = "Add"
});
//routeBuilder.MapControllerRoute("default", "{controller=Customer}/{action=Add}");
//routeBuilder.MapFallbackToController("Add", "Customer");
}
}
}
CustomerController.cs
using Microsoft.AspNetCore.Mvc;
namespace Lab4MVC.Controllers
{
public class CustomerController : Controller
{
public IActionResult Add(int Id)
{
return View("CustomerScreen");
}
public IActionResult Update()
{
return View();
}
public IActionResult Delete()
{
return View();
}
}
}
I am learning ASP.NET Core. Struggling to call Route with the pattern. I am able to call Controller using the default route.
When adding constraint it is not called. Also, please guide me on how to use the following pattern lets say Customer/New/1. Here I want to change my action name. Don't want to use Add URL.
Please help me. Thanks in advance.
In my opinion, the correct meaning you want to express should be that you don't want others to know what method you call in the background. Suppose you have a get request, and the original route is /Customer/Add? param=test, you want to display the path as /Person/Add through a custom method, similar to this requirement, right?
If it is like this,you can use Rewrite method.And you can refer to this Link.
It is worth noting that:app.UseRewriter() must be used before app.UseStaticFiles().
My endpoint routing is not working in my asp.net core 3.0 Api. I have seen similar questions but I am still not sure what is missing here.
I have the following in Startup.cs
{
public void ConfigureServices(IServiceCollection services)
{
services.AddOptions();
services.AddControllers()
.SetCompatibilityVersion(CompatibilityVersion.Version_3_0)
.AddNewtonsoftJson(options =>
{
options.SerializerSettings.Formatting = Formatting.Indented;
options.SerializerSettings.Converters.Add(
new Newtonsoft.Json.Converters.StringEnumConverter());
});
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
app.UseDeveloperExceptionPage();
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
"test",
"api/v1.0/{controller}/{id?}");
});
}
}
My Ping controller looks like:
public class PingController : ControllerBase
{
public IActionResult Get()
{
return Ok(true);
}
}
navigating to http://localhost//api/v1.0/Ping returns 404 page not found.
What am I missing here ? I also saw that MS suggests attribute routing for Web Apis but wanted to figure out why this is not working in the first place.
#rfcdejong was correct, it was missing {action} token.
The following correction fixed the problem.
endpoints.MapControllerRoute( "test", "api/v1.0/{controller}/{action=Get}/{id?}");
Follow this to add additional routing in .Net Core 3.1
endpoints.MapControllerRoute(
name: "prod", pattern: "product/item", new { controller="Product", action="Index"});
Can not route directly to an api endpoint.
My api controller "TestController" should be found at localhost:5511/api/Test/getCollection?testCode=A but it wont route and retuns a 404.
I've a .net core 3.0 RazorPages app but need to include a few api endpoints. I don't think my endpoint is getting routed.
In Startup.cs Configure method I have this:
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
endpoints.MapControllers();
});
Here is my route attribute on controller:
[Route("api/[controller]/[action]")]
GetCollection Action:
[HttpGet]
public IActionResult GetCollection(string testCode)
{
List<string> retval = ...get a string list
return Ok(retval);
}
[Edit]
------- ok a simpler example, wont route to api ---------
Razor pages .net core 3.0 app, add a new folder /api with a controller
Get a 404 when going to
https://localhost:44340/api/lookup/getsomething
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages();
services.AddMvc();
}
// 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("/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.MapRazorPages();
});
}
api controller
namespace aspnetcore1.Api
{
[Route("api/[controller]")]
[ApiController]
public class LookupController : ControllerBase
{
[HttpGet]
[Route("GetSomething")]
public IActionResult GetSomething()
{
return Ok("this is a test");
}
}
}
Your route attribute on the controller should be:
[Route("api/Test")]
And the route attribute on the method should be:
[HttpGet]
[Route("GetCollection")]
public IActionResult GetCollection(string testCode)
{
List<string> retval = ...get a string list
return Ok(retval);
}
Edit
It looks like this is missing in the Configure(IApplicationBuilder app, IWebHostEnvironment env) method:
app.UseMvc();
I have migrated an existing API project from 2.2 to 3.0 based on guidelines from this page.
Thus I've removed:
app.UseMvc(options =>
{
options.MapRoute("Default", "{controller=Default}/{action=Index}/{id?}");
});
and inserted:
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(name: "Default", pattern: "{controller=Default}/{action=Index}/{id?}");
});
But no controller and action would be bound. All I get for any API I call is 404.
How should I debug it and what do I miss here?
Update: The Startup.cs file is located in another assembly. We reuse a centralized Startup.cs file across many projects.
From Attribute routing vs conventional routing:
It's typical to use conventional routes for controllers serving HTML pages for browsers, and attribute routing for controllers serving REST APIs.
From Build web APIs with ASP.NET Core: Attribute routing requirement:
The [ApiController] attribute makes attribute routing a requirement. For example:
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
Actions are inaccessible via conventional routes defined by UseEndpoints, UseMvc, or UseMvcWithDefaultRoute in Startup.Configure.
If you want to use conventional routes for web api , you need to disable attribute route on web api.
StartUp:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
}
// 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.MapControllerRoute(
name: "Default",
pattern: "{controller=default}/{action=Index}/{id?}");
});
}
Web api controller:
//[Route("api/[controller]")]
//[ApiController]
public class DefaultController : ControllerBase
{
public ActionResult<string> Index()
{
return "value";
}
//[HttpGet("{id}")]
public ActionResult<int> GetById(int id)
{
return id;
}
}
This could be requested by http://localhost:44888/default/getbyid/123
I can recommend my solution.
Create your CUSTOM base controller like that.
[Route("api/[controller]/[action]/{id?}")]
[ApiController]
public class CustomBaseController : ControllerBase
{
}
And use CustomBaseController
public class TestController : CustomBaseController
{
public IActionResult Test()
{
return Ok($"Test {DateTime.UtcNow}");
}
}
Rout` api/Test/test
You should try:
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
It seems to not support conventional routing even in middleware like UseEndpoints and UseMvc
You can find that here