13

As someone pointed out in a comment, Razor pages doesn't need Controllers, like you're used to do in MVC. I also now Razor doesn't have a native handling of the button click event. To do something (in the "code-behind") when the user click a button we have at least two options:

  • use a submit button
  • use an ajax call

I find a LOT of examples for MVC that show how to define the Controller functions. But as said, I don't have one.

Hence I'm trying to understand both ways. Here my 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>

and here the cshtml.cs:

public class TestModel : PageModel { private readonly 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
}

Questions

  1. With the "Way1" (submit) I'm able to catch the click of a button, but with some drawbacks. By default the page is reloaded due to the post. Sometimes I don't need to change anything, but just call a C# function. But I don't understand how to handle multiple buttons. I.e. if I have 5 buttons, how to do something different for each one?

  2. With the "Way2" I did something wrong because the function in cs code is never reached and I get a Bad Request error (400). What did I miss?

3 Answers 3

22

Normal form submit

When doing a normal form submit, As per the convention, you need the handler method name to follow On{{HttpVerb}}{{YourHanderName}} format

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

Now make sure you have your submit button inside a form tag and you mentioned the asp-page-handler. The value of that attribute should be your handler name in the page model class (Way2)

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

The above code will generate the markup for button with a formaction attribute which is set to the url yourBaseUrl/YourPageName?data=foo&handler=Way2. When the use clicks on the submit button, it will post the form this url because formaction attribute value will override the default action url of the form. When the request is received, the razor pages framework will use this parameter (handler) and direct the request to the corresponding handler method.

Ajax call

You are getting a 400 (Bad Request) response because the framework expects the RequestVerificationToken as part of the posted request data. If you check the view source of the page, you can see a hidden input element with name __RequestVerificationToken inside the form. The framework uses this to prevent possible CSRF attacks. If your request does not have this information, the framework will return the 400 bad request.

To make your ajax code works, all you have to do is, send this explicitly. Here is a working sample

$("#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);
    });
});

Now since you are making an ajax call, it makes sense to return a json response

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

In the above example, we are using some jQuery code to get the input element with name __RequestVerificationToken and reading the value of it. A more robust approach would be injecting the IAntiforgery implementation to the view and using the GetAndStoreTokens method.

@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>
Sign up to request clarification or add additional context in comments.

6 Comments

Very good explanation! Now I understand a lot better what's happening. The first method works like a charm. I would ask you the last clarification about the ajax url: what is the right syntax here? My initial guess ("@Url.Action("Way2)") now leads to error 500
No. you need to use the formaction attribute value of your button.That is where you need to post to (it is same as the url i mentioned above). Simply check the view source.
Oh sorry about that. I thought it was just an example! Anyway it still answers with an error 500. Perhaps there's something else wrong in my code.
500 means, your code is crashing. Put a breakpoint in your OnPostWay2 and see what is happening.
Found. I didn't realize I have to put the asp-page-handler attribute even when I make an ajax call. Thank you very much.
|
1

In addition to the jQuery code shown that handles the click, you additionally have to include the name of the function in the asp-page-handler in order to route to the right function. If you don't have an asp-page-handler, the request will end up in the default OnPost() function. You want it to go to the OnPostWay2 function.

Code:

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

Comments

0

Here is another simple way in order if you want to perform any handlers and want just to navigate to another page:

<button type="button" class="btn" onclick="window.location.href = '/YourPage'">Button Title</button>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.