Estoy tratando de descifrar el uso de AJAX con Razor Pages.
He estado buscando en la web, pero cada ejemplo que he encontrado hace algo diferente, y la mayoría están incompletos o no para Razor Pages.
Hasta ahora, me he centrado en variaciones de algo como esto:
$.post('/?handler=Delete', 5, function (x) { alert(x); });Y luego mi modelo de página se ve así:
public void OnPostDelete(int id) { }Probé variaciones de esto pero, hasta ahora, no se llama a mi código C#.
Preguntas:
ACTUALIZAR:
Así que he estado trabajando con esto y esto es lo que tengo ahora:
$.ajax({ url: '?handler=Delete', data: { id: $(this).data('id') } }) .fail(function (e) { // Error alert(e.responseText); // Way too much info }) .done(function () { // Success }) .always(function () { // Always });Y mi manejador:
public void OnGetDelete(int id) { } De hecho, esto está llamando a mi controlador y finalmente conseguí que pasara el argumento id .
Como tengo una recompensa, esto es lo que me gustaría ver en una respuesta:
OnPostDelete() , no se llama al controlador. ¿Cómo haría una publicación?Dos sugerencia:
1- agregue la ruta de la página delante de la URL. (No estoy seguro si se menciona en tus palabras).
$.post('/{page_path}/?handler=Delete', 5, function (x) { alert(x); });2- Sigue la regla del mapa de rutas. Por ejemplo, está el 'id' en su función. La página puede haberse configurado como @page "{id:int}". Así que la URL debería ser algo como
$.post('/{page_path}/{id}/?handler=Delete', 5, function (x) { alert(x); });Puede pasar F12 para verificar la solicitud en la pestaña Red, es posible que vea un error de solicitud incorrecta 400.
Las páginas de Razor están diseñadas para protegerse automáticamente de los ataques de falsificación de solicitudes entre sitios (CSRF/XSRF) . No tienes que escribir ningún código adicional. La generación y validación de tokens antifalsificación se incluye automáticamente en Razor Pages. Aquí la solicitud falla, no hay AntiForgeryToken presente en la página.
Para la pregunta, podría agregar explícitamente usando @Html.AntiForgeryToken() Para agregar AntiForgeryToken, podemos usar cualquiera de los enfoques. Ambos enfoques agregan un tipo de entrada oculto con el nombre __RequestVerificationToken . La solicitud de Ajax debe enviar el token antifalsificación en el encabezado de la solicitud al servidor. Entonces, la solicitud de Ajax modificada parece,
@Html.AntiForgeryToken() @section Scripts { <script> $.ajax({ type: "POST", url: "/?handler=Delete&id="+5, beforeSend: function (xhr) { xhr.setRequestHeader("XSRF-TOKEN", $('input:hidden[name="__RequestVerificationToken"]').val()); }, success: function (x) { alert(x); }, failure: function (response) { alert(response); } }); </script>}
Dado que el script envía el token en un encabezado llamado X-CSRF-TOKEN, configure el servicio antifalsificación para buscar el encabezado X-CSRF-TOKEN:
public void ConfigureServices(IServiceCollection services) { services.AddRazorPages(); services.AddAntiforgery(o => o.HeaderName = "XSRF-TOKEN"); }Referencia: https://www.talkingdotnet.com/handle-ajax-requests-in-asp-net-core-razor-pages/
Así es como me gusta hacerlo:
Configura tu Javascript
//If you're returning a object, configure it var yourObject = { field1: "value1", field2: "value2" }; //setup ajax $.ajax({ data: yourObject, type: "POST", url: "urltoyourhandler/delete" //you can add other paramters here as well by doing ?parm=value success: function(data){ //do success stuff here //based off my handler code below: if(data.success){ console.log("Success!"); } else{ console.log("Failed for some reason!"); } } error: function(){ //do error stuff here //gets called if there is a issue contacting the URL or if there is a server error like 500 } });Configurando su controlador. Para mis operaciones CRUD, me gusta hacer un controlador CRUD para manejar todo
[BindProperty] public YourClass Name { get; set; } //set handler to only accept POST and set a URL for it. URL should be to the same folder you're in //the 'delete' in route doesn't have to match the function name but it's less confusing if it does [HttpPost, Route("RouteToThisHandler/delete)] public async Task<IActionResult> Delete() { //verify data and the do something with it //I like returning a JsonResult. Add whatever data you want. I like returning success //with true or false and some other data if needed return new JsonResult(new { success: true, importantInfo: "This is important" }); }Ajax tiene más opciones de configuración para brindarle más información sobre cualquier error del servidor que ocurra
En cuanto al token antifalsificación, Microsoft dice:
El middleware antifalsificación se agrega al contenedor de inyección de dependencia cuando se llama a una de las siguientes API en Startup.ConfigureServices:
- AñadirMvc
- MapRazorPages
- MapControllerRoute
- MapaBlazorHub
Aquí hay un enlace de Microsoft sobre el token antifalsificación: https://docs.microsoft.com/en-us/aspnet/core/security/anti-request-forgery?view=aspnetcore-3.1
Investigué algunas cosas, qué sucede cuando pasa una cadena de AJAX en lugar de un número entero y cómo las diferentes rutas afectan la llamada (vea la nota interesante a continuación si tiene tiempo) Pero sobre todo, todo lo que encontré es que Razor Pages son bastante indulgente y todo parecía funcionar. Como mencioné, incluso pasar una cadena en la que una id de tipo entero aún golpea el método del controlador (simplemente me dio un default(int) )
Creé este repositorio solo para explorar: https://github.com/EntityAdam/RazorPageHandlers
El principal bloqueador, como señaló @Yan, es el token Anti-Falsificación. Eso es realmente lo único que hizo que un controlador no alcanzara un punto de interrupción. Como se sugirió, revise la pestaña de su red para ver si hay solicitudes fallidas o la consola para ver si hay un código JavaScript defectuoso.
Desde su fragmento, para cambiarlo a OnPostDelete , necesitaría usar el tipo POST en la llamada AJAX E incluir el token antifalsificación.
$.ajax({ type: 'POST', headers: { "RequestVerificationToken": $('input[name="__RequestVerificationToken"]').val() }, url: '?handler=Delete', data: { id: $(this).data('id') } }) .fail(function (e) { // Error alert(e.responseText); // Way too much info }) .done(function () { // Success }) .always(function () { // Always }); Otro tema que no vi discutido es ¿de dónde viene este token? Lo genera automáticamente Razor cada vez que hay un elemento <form> . Si no tiene un elemento <form> , puede generar tokens cuando los necesite, consulte el bloque @functions {} en este artículo de MSDN . También hay escenarios en los que CSRF es inútil o no es necesario y también puede desactivar la protección contra falsificaciones si no lo necesita (esa es una discusión completamente diferente).
Mis críticas al enfoque son opiniones, así que tómalas o déjalas.
Para esta demostración, utilicé la siguiente directiva @page
@page "{id?}"En la parte HTML de los formularios como:
<form method="post" asp-page-handler="Delete"> <input type="hidden" name="id" value="1" /> <button class="btn btn-danger">Delete</button> </form> Estoy usando el asistente de etiquetas asp-page-handler para ayudar a generar la URL correcta. Para el controlador Create, con esa directiva @page , el asistente de etiquetas presenta un destino de formulario de /?handler=Create
Si cambia esa directiva @page con @page "{handler?}/{id:int?}" , el asistente de etiquetas descubre la ruta que ahora es /Delete . ¿Pero adivina que? Las llamadas AJAX funcionan con cualquiera de las directivas @page , aunque la URL en AJAX está codificada para ?handler=Delete'