web-dev-qa-db-fra.com

ASP.NET Core 2, cliquez sur le bouton avec des pages Razor sans MVC

Comme quelqu'un l'a souligné dans un commentaire, les pages Razor n'ont pas besoin de contrôleurs, comme vous en avez l'habitude dans MVC. J'ai également maintenant Razor n'a pas de gestion native de l'événement de clic de bouton. Pour faire quelque chose (dans le "code-behind") lorsque l'utilisateur clique sur un bouton, nous avons au moins deux options:

  • utiliser un bouton soumettre
  • utiliser un appel ajax

Je trouve BEAUCOUP d'exemples pour MVC qui montrent comment définir les fonctions du contrôleur. Mais comme je l'ai dit, je n'en ai pas.

Par conséquent, j'essaie de comprendre les deux façons. Voici mon test cshtml:

<form method="post">
    <input type="submit" class="btn btn-primary" value="way1">Way 1/>
</form>

<button id="btn" type="button" class="btn btn-primary" value="way2">Way 2</button>

<script>
$(document).ready(function() {
    $("#btn").click(function (e) {
        e.preventDefault();
        $.ajax({
            url: "@Url.Action("Way2")",
            type: "POST",
            data: "foo",
            datatype: "text",
            success: function (data) {
                alert(data);
            }
        });
        return false;
    });
});
</script>

et ici le cshtml.cs:

classe publique TestModel: PageModel {privé en lecture seule MyContext _context;

public TestModel(MyContext context)
{
    _context = context;
}

public IActionResult OnPost()
{
    // here I can put something to execute 
    // when the submit button is clicked
}

public ActionResult Way2(string data)
{
    // this is never triggered
}

Des questions

  1. Avec le "Way1" (soumettre), je suis capable d'attraper le clic d'un bouton, mais avec quelques inconvénients. Par défaut, la page est rechargée en raison de la publication. Parfois, je n'ai rien à changer, mais j'appelle simplement une fonction C #. Mais je ne comprends pas comment gérer plusieurs boutons. C'est à dire. si j'ai 5 boutons, comment faire quelque chose de différent pour chacun?

  2. Avec le "Way2", j'ai fait quelque chose de mal car la fonction dans le code cs n'est jamais atteinte et j'obtiens une erreur Bad Request (400). Qu'est-ce que j'ai raté?

8
Mark

Soumission du formulaire normal

Lors de la soumission d'un formulaire normal, conformément à la convention, vous devez utiliser le nom de la méthode du gestionnaire pour suivre On{{HttpVerb}}{{YourHanderName}} format

public ActionResult OnPostWay2(string data)
{
    // to do : return something
}

Assurez-vous maintenant que votre bouton d'envoi se trouve dans une balise form et que vous avez mentionné le asp-page-handler. La valeur de cet attribut doit être le nom de votre gestionnaire dans la classe de modèle de page (Way2)

<form method="POST">       
    <button type="submit" asp-route-data="foo" asp-page-handler="Way2">Way 2</button>
</form>

Le code ci-dessus générera le balisage pour le bouton avec un formaction attribut qui est défini sur l'url yourBaseUrl/YourPageName?data=foo&handler=Way2. Lorsque l'utilisateur clique sur le bouton Envoyer, il publiera le formulaire cette URL car la valeur de l'attribut formaction remplacera l'URL d'action par défaut du formulaire. Lorsque la demande est reçue, le framework de pages de rasoir utilisera ce paramètre (handler) et dirigera la demande vers la méthode de gestionnaire correspondante.

Appel Ajax

Vous obtenez une réponse 400 (Bad Request) car le framework attend le RequestVerificationToken dans le cadre des données de requête publiées. Si vous vérifiez la source d'affichage de la page, vous pouvez voir un élément d'entrée masqué avec le nom __RequestVerificationToken à l'intérieur du formulaire. Le cadre utilise cela pour empêcher d'éventuelles attaques CSRF. Si votre demande ne contient pas ces informations, le framework retournera la 400 mauvaise requête.

Pour que votre code ajax fonctionne, il vous suffit de l'envoyer explicitement. Voici un échantillon de travail

$("#btn").click(function(e) {
    e.preventDefault();

    var t = $("input[name='__RequestVerificationToken']").val();
    $.ajax({
        url: $(this).attr("formaction"),
        headers:
        {
            "RequestVerificationToken": t
        },
        type: "POST",
        data: { data: 'foo2' },
    }).done(function(data) {
        console.log(data);
    }).fail(function(a, v, e) {
        alert(e);
    });
});

Maintenant que vous effectuez un appel ajax, il est logique de renvoyer une réponse json

public ActionResult OnPostWay2(string data)
{
    return new JsonResult("Received "+ data + " at "+DateTime.Now);        
}

Dans l'exemple ci-dessus, nous utilisons du code jQuery pour obtenir l'élément d'entrée avec le nom __RequestVerificationToken et en lisant la valeur. Une approche plus robuste consisterait à injecter l'implémentation IAntiforgery dans la vue et à utiliser la méthode GetAndStoreTokens.

@inject Microsoft.AspNetCore.Antiforgery.IAntiforgery Xsrf
@functions{
    public string GetAntiXsrfRequestToken()
    {
        return Xsrf.GetAndStoreTokens(Model.HttpContext).RequestToken;
    }
}
<script>
     $(function () {

         $("#btn").click(function(e) {
             e.preventDefault();
             var t = '@GetAntiXsrfRequestToken()';
             $.ajax({
                      url: $(this).attr("formaction"),
                      headers:
                      {
                          "RequestVerificationToken": t
                      },
                      type: "POST",
                      data: { data: 'foo2' },
             }).done(function(data) {
                     console.log(data);
             }).fail(function(a, v, e) {
                     alert(e);
             });
         });
    })
</script>
11
Shyju