0
votes

I am creating an application that presents users with a form. When the user submits the form, my application takes those values and formats them into a query string. This string is then used to make a call to a third party API. The application is written in C# using an ASP.NET Core Razor Pages template in Visual Studio 2019. I had first experimented with creating an HTTPClient and sending an HTTPRequestMessage to the third party API using hard-coded values in a console app, which worked perfectly. However, when moving my code into a Razor Pages application to add a front end for the app I can't seem to get the application to call the code I created. Since I am only taking form values and passing them in a query string to a third-party API, which doesn't require me to define my own model, I decided to use Razor Pages instead of ASP.NET MVC.

This is the Index.cshtml page as I set it up in my application:

@page
@model IndexModel
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@{
    ViewData["Title"] = "Home page";
}

    <div>
        <form asp-page-handler="ProcessRequest" method="post">
            <label for="FirstName">First Name:</label>
            <input type="text" name="FirstName" value="" />
            <label for="LastName">Last Name:</label>
            <input type="text" name="LastName" value="" />
            <label for="Email">Email:</label>
            <input type="text" name="Email" value="" />
            <button type="submit">Send Request</button>
        </form>
    </div>

As you can see, it is just a simple form with three input fields, nothing fancy.

The underlying Index.cshtml.cs file containing the model logic has the following code:

public class IndexModel : PageModel
{
    static HttpClient myAppHTTPClient = new HttpClient();

    public async void OnPostProcessRequestAsync()
    {            
        string firstName, lastName, email;
        string host = "https://thirdparty.app.com:443/";
        string pathname = "path/to/api/endpoint/?operation=create";

        firstName = "Test";
        LastName = "User";
        email = "[email protected]";

        string path = pathname + "&first_name=" + firstName + "&last_name=" + lastName + "&email=" + email;
        string requestUrl = host + path;

        HttpRequestMessage httpRequestMessage = new HttpRequestMessage();

        try
        {
            HttpResponseMessage responseMessage = await myAppHTTPClient.PostAsync(requestUrl, httpRequestMessage.Content);
            HttpContent content = responseMessage.Content;
            string message = await content.ReadAsStringAsync();
            Console.WriteLine("The output from thirdparty is: {0}", message);
            RedirectToPage();
        }
        catch (HttpRequestException exception)
        {
            Console.WriteLine("An HTTP request exception occurred. {0}", exception.Message);
        }
    }
}

The documentation for ASP.NET Razor Pages says that when you have an asp-page-handler tag helper in your form submitting the form will call the page handler method OnPost[method_name]Async(). In my case, the line <form asp-page-handler="ProcessRequest" method="post"> in the form should call the public async void OnPostProcessRequestAsync() method. However, this isn't working as I thought it would. I tried using different tag helpers in the form and in the submit button. Is there a way to get the Razor Page to call the method that runs my code. I know I am missing the RedirectToPage() method but I first want to get the method call to work.

1
I'm not familiar with Razor pages but an async method should return a Task/Task<T>, void should only be returned in case of async event handlers. - vdL
Yeah, I am not too clear on how a Razor pages app differs from an MVC app. Now that you mentioned it, I did notice how the OnPostAsync() methods in the documentation examples return a Task<IActionResult>. Not sure what a Task<IActionResult> is or how I am supposed to return it. Any ideas? - Eddie
What do you mean by not working ? the function isn't fired when clicking the submit button ? - Nan Yu
Yes, that's what I mean by not working. - Eddie
Add a return statement before RedirectToPage() and change the handler to return a Task<IActionResult>, not void. You will also need to return from the catch block. And Console.WriteLine is pointless in an ASP.NET app. - Mike Brind

1 Answers

1
votes

Though two people on this thread already suggested the answer, I didn't see a way where I could mark their comments as having answered the question. So, to be fair and give credit where credit is due, their suggestions allowed me to fix my code. Basically, I had defined the page handler method incorrectly. I had defined it as:

public async void OnPostProcessRequestAsync()...

However, this type of application requires page handler methods to return something like Task. When changing the return type from void to Task this worked perfectly. My guess is that since I am defining this code asynchronously, the return value must be something asynchronous. Since the Task<> class is used for Threading (async) code it makes sense that this would work.