I'm fairly new, relatively speaking to .NET Core and MVC Core having previously been used to .NET 4.x and MVC 5, so please bear with me if I'm asking something obvious; I couldn't find an answer by searching any way.
Stuff used:
So I have a controller with actions like the following:
[Area("SomeArea")]
public class SomeNameController : Controller
{
public SomeNameController(..injected stuff...) { }
[HttpGet]
public PartialViewResult AddDialog() {
...
}
[HttpPost]
public async Task<IActionResult> AddDialog(MyDialogModel dialogModel) {
...
}
[HttpDelete]
[Route("DoSomeDeletion/{uniqueIdentifier}")]
public async Task<JsonResult> DoSomeDeletion(int uniqueIdentifier)
{
...
return Json(result);
}
}
In the Startup.cs where stuff gets configured amongst other things I have:
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
endpoints.MapBlazorHub();
endpoints.MapControllerRoute(
name: "areas",
pattern: "{area:exists}/{controller=index}/{action=Index}/{id?}");
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=index}/{action=Index}/{id?}");
endpoints.MapFallbackToPage("/_Host");
});
I have the following JS in my page to add a click handler and do an AJAX delete:
$("#MyGrid").on('click', '.js-delete-btn', function (e) {
e.preventDefault();
var url = this.href,
data = $("#GridForm").serializeObject();
$.ajax({
method: "DELETE",
url: url,
data: data
})
.done(function (jqXHR, textStatus) {
toastr.success("Yay! Deleted successfully", null, {
timeout: 5000,
onHidden: function () { window.location.reload(); }
});
})
.fail(function (jqXHR, textStatus, errorThrown) {
toastr.error("Uh-oh something went wrong", null, { timeout: 5000 });
});
});
In the above the href used for the AJAX request will be something like /SomeArea/SomeName/DoSomeDeletion/356
The form that gets serialized contains a anti-forgery token from when I was trying the MVC action with [HttpPost]
If I set a breakpoint in the DoSomeDeletion action it will never get hit. However, if I take the Route attribute off of it then it will get hit.
I haven't used attributes for routing before so maybe I'm missing something, but in MVC 5 in .NET 4.8 I never had these kinds of issues, I could have 1 or more route values come from the URL and be called whatever I wanted.
What is going on? Why can't I use route value names that I want to use?
After rereading the MS docs, prompted by @mason in the comments, the bit that didn't quite stick in my head is the all or nothing usage of attribute routing vs. classic routing.
To make this work, based on the original question, I had to add attributes to the controller and the action methods as follows:
[Area("SomeArea")]
[Route("[area]/[controller]/[action]")]
public class SomeNameController : Controller
{
public SomeNameController(..injected stuff...) { }
[HttpDelete]
[Route("{uniqueIdentifier}")]
public async Task<JsonResult> DoSomeDeletion(int uniqueIdentifier)
{
...
return Json(result);
}
}
I could also have just put it all on the action as follows:
[Area("SomeArea")]
[Route("[area]/[controller]/[action]")]
public class SomeNameController : Controller
{
public SomeNameController(..injected stuff...) { }
[HttpDelete]
[Route("[area]/[controller]/[action]/{uniqueIdentifier}")]
public async Task<JsonResult> DoSomeDeletion(int uniqueIdentifier)
{
...
return Json(result);
}
}
I took the former route because in the real code there are naturally multiple actions and so didn't want to repeat things.