I am trying to route url with and without parameter to two different methods but for some reason it always start first one.
Here is controller code:
public class ProductController : Controller
{
[Route("")]
[Route("Product")] //If i delete this one then it works how it is intended
public IActionResult Index()
{
//It always start this one
....
}
[Route("Product/{GroupID?}")]
public IActionResult Index(int GroupID)
{
....
}
}
Related
I remember from ASP.NET Web API that it's sufficient to prefix Web API REST method names with HTTP commands (e.g. GetList() => HTTP GET, Delete() => HTTP DELETE) to have incoming calls appropriately routed.
I also remember that in ASP.NET Web API parameter matching takes place so that even Get(int id) and Get(int id, string name) get automatically and appropriately routed without requiring any attributes.
public class MyController
{
public ActionResult Get(int id) => ...
public ActionResult Get(int id, string name) => ...
public ActionResult DeleteItem(int id) => ...
}
Isn't this all available in ASP.NET Web API Core?
You just need to add the Route to the top of your controller.
Specify the route with api, controller and action:
[Route("api/[controller]/[action]")]
[ApiController]
public class AvailableRoomsController : ControllerBase
{
...
}
Neither could we do action overloads nor prefix action name as Http verb.The way routing works in ASP.NET Core is different than how it did in ASP.NET Web Api.
However, you can simply combine these actions and then branch inside, since all params are optional if you send as querystring
[HttpGet]
public ActionResult<string> Get(int id, string name)
{
if(name == null){..}
else{...}
}
Or you need to use attribute routing to specify each api if you send in route data:
[HttpGet("{id}")]
public ActionResult<string> Get(int id)
{
return "value";
}
[HttpGet("{id}/{name}")]
public ActionResult<string> Get(int id, string name)
{
return name;
}
Refer to Attribute Routing,Web Api Core 2 distinguishing GETs
The aspnetcore webapi controllers do not natively support inference of http verbs by naming convention, but allow you to create your own convention and achieve this behavior.
Create your convention
public class MyConvention : IApplicationModelConvention
{
public void Apply(ApplicationModel application)
{
foreach(var controller in application.Controllers)
{
foreach(var action in controller.Actions)
{
if (action.ActionName.StartsWith("Post"))
{
action.Selectors.First().ActionConstraints.Add(new HttpMethodActionConstraint(new[]{ "POST" }));
}
}
}
}
}
Then register it in Program/Startup:
builder.Services.AddControllers(configure => configure.Conventions.Insert(0, new MyConvention()));
This is available for Core 2 yes, but the way that I know how to do it is something like this
[Route("api/[controller]")]
[ApiController]
public class AvailableRoomsController : ControllerBase
{
private readonly ApplicationContext _context;
public AvailableRoomsController(ApplicationContext context)
{
_context = context;
}
// GET: api/AvailableRooms
[HttpGet]
public async Task<ActionResult<IEnumerable<AvailableRoom>>> GetAvailableRooms()
{
return await _context.AvailableRooms.ToListAsync();
}
// POST: api/AvailableRooms
[HttpPost]
public async Task<ActionResult<AvailableRoom>> PostAvailableRoom(AvailableRoom availableRoom)
{
_context.AvailableRooms.Add(availableRoom);
await _context.SaveChangesAsync();
return CreatedAtAction("GetAvailableRoom", new { id = availableRoom.Id }, availableRoom);
}
[HttpPut] .... etc
}
Now depending on what kind of REST action you specify and what type of model you send to "api/AvailableRooms" if the proper Action exists it will be chosen.
Visual Studio 2019 and I think 2017 can create a controller such as this automatically if you right click your Controllers folder and click Add->Controller and then choose "API Controller with actions, using Entity Framework" and choose one of your Model classes.
What I basically want to know is this:
Suppose I have a method annotated with #RequestMapping and the value "/test/ajax". Can I make that specific method accessible only to internal calls but not to the client? If I run an ajax request on that url from within the server it should work normally, but if I run it directly from the browser it should return a 403.
Is that in any way possible?
add the spring annotation #CrossOrigin on controller layer for example
also, follow the given link https://spring.io/blog/2015/06/08/cors-support-in-spring-framework
#CrossOrigin
#RestController
#RequestMapping("/account")
public class AccountController {
#GetMapping("/{id}")
public Account retrieve(#PathVariable Long id) {
// ...
}
#DeleteMapping("/{id}")
public void remove(#PathVariable Long id) {
// ...
}
}
If you allow only a method pass like this
#RestController
#RequestMapping("/account")
public class AccountController {
#CrossOrigin
#GetMapping("/{id}")
public Account retrieve(#PathVariable Long id) {
// ...
}
#DeleteMapping("/{id}")
public void remove(#PathVariable Long id) {
// ...
}
}
i am currently trying to generate this url "/Cloud/Hosting/RoaringPenguin/Manage/Exclusions".
Here is the area registration
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Hosting_default",
"Cloud/Hosting/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional }
);
}
here is the controller
public class RoaringPenguinController : PortalControllerBase
{
public ActionResult Exclusions()
{
return View("Exclusions");
}
}
i have tried added a route onto the action itself like so
[Route("Manage/Exclusions")]
public ActionResult Exclusions()
I have also tried adding some attributes to the controller itself
[RouteArea("Hosting")]
[RoutePrefix("RoaringPenguin")]
public class RoaringPenguinController : PortalControllerBase
but that doesn't seem to work either. If i leave all the attributes off then the final url i get is "/Cloud/Hosting/RoaringPenguin/Exclusions".
Does anyone know how i can get the "Manage" in the url as well?
Just to confirm i have the following set in my RegisterRoutes method under the RouteConfig class
routes.MapMvcAttributeRoutes();
Any help is appreciated. Thanks
Your default area route doesn't allow for the "Manage/Exclusions" part on the end. If you made the URL just /Cloud/Hosting/RoaringPenguin/Exclusions (minus the Manage part of the path) it would work fine.
If you need the route to be exactly that, then attribute routing is your best bet. However, your mentioned attempts at that are all missing something or another. Your controller should be decorated with both RouteArea and RoutePrefix to compose the first part of the path:
[RouteArea("Hosting", AreaPrefix = "Cloud/Hosting")]
[RoutePrefix("RoaringPenguin")]
public class RoaringPenguinController : Controller
However, it's typical to actually implement a base controller when dealing with areas, so that you can specify RouteArea in just one place:
[RouteArea("Hosting", AreaPrefix = "Cloud/Hosting")]
public class HostingBaseController : Controller
[RoutePrefix("RoaringPenguin")]
public class RoaringPenguinController : HostingBaseController
Then, on your action:
[Route("Manage/Exclusions")]
public ActionResult Exclusions()
As you had.
Try with this code
[RouteArea("AreaName", AreaPrefix = "Cloud/Hosting")]
[RoutePrefix("RoaringPenguin")]
public class SampleController : Controller
{
[Route("Manage/Exclusions")]
public ActionResult Exclusions()
{
return View("Exclusions");
}
}
or
[RoutePrefix("Cloud/Hosting/RoaringPenguin")]
public class RoaringPenguinController : PortalControllerBase
{
[Route("Manage/Exclusions")]
public ActionResult Exclusions()
{
return View("Exclusions");
}
}
This will be the first line
routes.MapMvcAttributeRoutes();
After that only you have to write this line
AreaRegistration.RegistrationAllAreas();
In MVC5 you could set the default route using the following attribute on a controller?
[Route("{action=index}")]
What is the equivalent of this in MVC6?
Update
This is the code I had in MVC5
[Route("{action=index}")]
public class StaticPagesController : Controller
{
public ActionResult About()
{
return View();
}
public ActionResult Contact()
{
return View();
}
public ActionResult Index()
{
return View();
}
}
I have not been able to work out how to do the equivalent in MVC6 but I've been able to get the same functionality working using the following:
[Route("[action]")]
public class StaticPagesController : Controller
{
public ActionResult About()
{
return View();
}
public ActionResult Contact()
{
return View();
}
[Route("/[action]")]
[Route("/")]
public ActionResult Index()
{
return View();
}
}
You can decorate your specific action method which you want to be the default action with Route attribute and pass [controller] as the route template to that. So anytime you get a request for yoursite/yourcontroller, the incoming request will be redirected to this specific action method.
public class SettingsController : Controller
{
public IActionResult Index()
{
return View();
}
[Route("[controller]")]
public IActionResult OtherIndex()
{
return Content("This will be the response for mySite/Settings request");
}
}
Edit : As per the comment
I don't want to include the controller name in the URL.I want it to be
domain.com/About rather than domain.com/StaticPages/About
Using attribute routing, you can decorate your action method with the Route attribute and give [action] as the template name.
public class StaticPagesController : Controller
{
[Route("[action]")]
public IActionResult About()
{
// This action method will be executed for "yourSite/About" request
return View();
}
}
With the above approach, you cannot have 2 action method's with the same name in your app ( Ex : You cannot have an About action method in HomeController and StaticPagesController)
I get this error when I hit the url Shop/Checkout
The request has found the following matching controller types:
shopmvc.Controllers.HomeController
shopmvc.Controllers.ProductsController
My HomeController.cs:
[Route("{action=index}")]
public class HomeController : Controller
{
[Route("Shop/Checkout")]
public ActionResult Checkout()
{
}
}
My ProductsController.cs:
[RoutePrefix("Shop")]
[Route("{action=index}")]
public class ProductsController : Controller
{
[HttpGet]
[Route("{brand}/{category}/{subcategory?}/{page:int?}")]
public ActionResult Index(string brand, string category, string subcategory, int? page, SortOptions currentSort = SortOptions.SinceDesc)
{
}
[HttpGet]
[ActionName("Details")]
[Route("{brand}/{category}/{productid}")]
public ActionResult Details(int productid)
{
}
}
I get it that both routes have Shop in it, but I have no clue how to resolve this. This is the razor code in my shared layout:
<a href="#Url.Action("checkout", "Home" )">
The issue is that "Checkout" is valid as a parameter for brand in your ProductController routes. There's no intrinsic order to routes with attribute routing, so you have to be more careful to make sure only one route can truly match the URL. In your case here, you can simply do something like:
[Route("{brand:regex((?!Checkout))}/...")]