Does the Controller's HttpPost ActionResult get called at the start of, during, or after the form's submit event?

StackOverflow https://stackoverflow.com/questions/18365504

Domanda

This is a followup to my question here: Why are my "replacement parameters" getting transformed into empty strings?

Okay, maybe somebody can help me understand what's going on here (note that I didn't write this code, so I'm approaching it from the perspective of a problem bear that has just been heli-dropped into unfamiliar terrain).

As it seemed more natural/conventional to do so, I changed my handler from a submit button click handler to the form's submit handler:

$("form").submit(function () {

The model values that are causing the whole process to fail being they are being resolved to empty strings (GUID, SerialNumber, and ReportName) are declared in the corresponding model's base class:

public class ReportModelCore
{
    public string GUID { get; set; }
    public string SerialNumber { get; set; }
    public string ReportName { get; set; }
    public bool DataSourceSuccess { get; set; }
    public string DataSourceMessage { get; set; }
    public string message { get; set; }
}

...and these core members are conditionally assigned values in the Controller:

model.SerialNumber = Serial.ToString();
model.ReportName = "ReceiptCollection";

DatasourceCreatorResultContract result = Operations.CreateDataSource(criteria);

if (result.type == ResultType.Success)
{
    model.GUID = result.GUID;
    . . .
}
else if (result.type == ResultType.SuccessWithAlert)
{
    model.GUID = result.GUID;
    . . .
}
else // Failure < no GUID assigned in diesem Fall
{
    . . .

...but I don't grok how they are expected to have values in the form's submit handler, where they are referenced:

    . . .
    if (resultsText == "0") {
        $("#NumberOfResults").css("color", "red");
    } else {
        var href = '/@ConfigurationManager.AppSettings["ThisApp"]/TLDCriteria/LoadReport';
        // report_parms (sic) is referenced from LoadReport
        var report_parms = {
            GUID: "@Model.GUID",
            SerialNumber: "@Model.SerialNumber",
            ReportName: "@Model.ReportName"
        };
        window.open(href, "report_window", "resizable=1, width=850, left=" + (screen.width / 2 - 425));
    }
. . .

IOW: When does the Controller's [HttpPost] ActionResult get fired? Before the form submit event finishes? If so, when exactly?

If not, why is this code referencing those model members which could not have been assigned values yet (and when they are empty strings, as they currently are, it causes the whole kit and kaboodle to ceremoniously but ignominiously fail)?

UPDATE

report_parms are, as the comment notes, referenced from LoadReport, which is a Silverlight-infested file with:

<script type="text/javascript">
    function get_user_name() {
        return "@User.Identity.Name";
    }

    function get_xml_data() {
        return window.opener.xml_data;
    }

    function get_receipt_parms() {
        return window.opener.receipt_parms;
    }

    function get_report_parms() {
        return window.opener.report_parms;
    }
</script>

Stepping through it in Firefox > Script, it indeed shows the values of those three members of "report_parms" being empty strings; I'm not surprised, but again: is there a reason why somebody would expect those vals to be populated at this point - and do they need to be? If so, how?

UPDATE 2

MisterJames,

Yes, there is a:

return View(model);

...at the end of the [HttpPost] ActionResult, but it turns out it is never reached; apparently another problem is preventing that from occurring; acutally, it seems like kind of a "chicken-and-egg" problem: I was thinking that the reason this code:

DatasourceCreatorResultContract result = Operations.CreateDataSource(criteria);

...was failing was because the criteria object passed to CreateDataSource() was not quite right, and that was because those report_parms were empty; But it might be, OTOH, that the problem lies elsewhere. To wit: the "if (result.type == ResultType.Success)" line is never reached, because the code fails due to lack of proper authentication, apparently.

I thought this was caused by my report_parms problem, but perhaps my report_parms problem is caused by this!

The entire section of code is:

        . . .
    model.SerialNumber = Serial.ToString();
    model.ReportName = "ReceiptCollection";

    DatasourceCreatorResultContract result = Operations.CreateDataSource(criteria);

    if (result.type == ResultType.Success) // <-- this is not reached; "conn.Open();" in another class fails before it can be
    {
        model.GUID = result.GUID;
        model.DataSourceSuccess = true;
        model.NumberOfResults = result.Count;
        model.message = String.Format("{0} results", result.Count);
    }
    else if (result.type == ResultType.SuccessWithAlert)
    {
        model.GUID = result.GUID;
        model.DataSourceSuccess = true;
        model.NumberOfResults = result.Count;
        model.message = result.Message;
    }
    else // Failure
    {
        model.DataSourceMessage = result.Message;
        model.DataSourceSuccess = false;
        model.NumberOfResults = 0;
        model.message = result.Message;
    }
}
return View(model);
È stato utile?

Soluzione

Clay, you'll need to make sure that after populating the model that the controller actually passes the values to the view. You should see something like:

return View(model);

Your view is typed to that model (which I saw from your other question), and therefore when you pass in the model to the View method, you're actually instructing the framework to work with that set of data as it builds the view.

I agree that some of this seems magical, but keep in mind that these are just classes and methods. Your controller inherits from a base controller that has a method called "View" on it. What you're doing is passing an object to that method, which in turn injects that into the Razor view engine to generate a result - an HTML page that is rendered and returned to the browser.

To your question, the form submit (which happens on the client) and the invocation of the ActionResult (which happens on the server) are only connected by virtue of your web browser making a request and paying attention to the result. The form is fully submitted as part of your browser's request. The method is not invoked until the server receives the full request (and creates an instance of your controller, etc).

Your typical Asp.Net MVC flow might be something like:

  1. A browser request results in ActionResult method being invoked. Being a form, you likely load up a view model and pass it to the view.
  2. The view is processed by the Razor view engine. The model that is passed in will be supplied to the engine and used throughout the view.
  3. The browser (erm...user) submits the form. The values are put into a request object and form encoded.
  4. The MVC framework spins up again, creates a controller, uses model binding to push the form-encoded values into your parameters - if it can - and invokes your HttpPost method.

If you are not seeing the values in the view (the HTML resultant page) in step 2, it is best to set a breakpoint in step 1 where you can evaluate why the model is not being populated.

Hope this helps some. If you want a more granular view of the pipeline, you can check out this post: Asp.Net MVC Pipeline.

Cheers.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top