简体   繁体   中英

ViewModel disappears after calling from a child action

I have the following situation:

  • A user can post a comment on a order
  • to display the comment form, I am calling @{Html.RenderAction("CreateComment", "Order", new { orderId = Model.Id, orgId = Model.OrganisationId });} on the Details view for the order
  • Once the user posts their comment, I need to redirect back to the Details view of the order
  • However, when calling RedirectToAction , I get :

    Child actions are not allowed to perform redirect actions.

To resolve this, I tried calling this insead of Redirect :

return View("Details", new { id = viewModel.OrderId });

But now I'm seeing this weird error:

The model item passed into the dictionary is of type '<>f__AnonymousType4`1[System.Int32]', but this dictionary requires a model item of type 'ViewOrderViewModel'.

Which seems like it's complaining that I am not passing a ViewModel to the view.

However, if you look at the Details controller action which I am callilng, it actually accepts an int and builds the ViewModel there (I can see that this action is still hit after making the above change):

public ActionResult Details(int id)
{
    var orderViewModel = orderManager.Select(id);
    return View(orderViewModel);
}

What is going on here? Why can't I just call the actions using the id route value, as I normally do? What is happening to my ViewOrderViewModel ?

Any advice is much appreciated thank you.


Update to add code

Order Details.cshtml

This is where I am dispalying the comments form, and where I need to redirect to at the end of all this. The url looks loks ~/order/details/14 .

The error seems to be thrown on the line @{Html.RenderAction("CreateComment", "Order", new { orderId = Model.Id, orgId = Model.OrganisationId });} :

Child actions are not allowed to perform redirect actions.

@using Web.Resources.Headers

@model Web.Models.ViewOrderViewModel

<div class="container">
    <h4>@Model.Name</h4>
    <hr />
    <div class="col-xs-12">

        <h4>Comments</h4>
        <hr />

        <div class="col-xs-12 col-sm-6">
            @foreach (var comment in Model.Comments)
            {
                @comment.Content
            }
        </div>

        <div class="col-xs-12 col-sm-6">
            @{Html.RenderAction("CreateComment", "Order", new { orderId = Model.Id, orgId = Model.OrganisationId });}
        </div>
    </div>
</div>

CreateComment.cshtml

The form to post a comment

@using Microsoft.AspNet.Identity

@model Web.Models.NewCommentViewModel

@using (Html.BeginForm()) 
{
    @Html.AntiForgeryToken()

    <div class="form-horizontal">
        @Html.ValidationSummary(true, "", new { @class = "text-danger" })

        @Html.HiddenFor(model => model.OrderId)
        @Html.HiddenFor(model => model.OrganisationId)
        @Html.HiddenFor(model => model.UserId)

        <div class="form-group has-feedback">
            <div class="col-xs-12" style="padding:0px;">
                @Html.TextAreaFor(model => model.Content, new { @class = "form-control", placeholder = Html.DisplayNameFor(model => model.Content) })
                <span class="glyphicon glyphicon-option-horizontal form-control-feedback"></span>
            </div>
        </div>

        <div class="form-group">
            <div class="pull-right">
                <input type="submit" value="Create" class="btn btn-default" />
            </div>
        </div>
    </div>
}

OrderController

Here you can see the controller methods used for dispalying the comment form and posting the comment to the database ('Redirect' method failed with the same error about child actions):

public ActionResult CreateComment(int orderId, int orgId)
{
    var viewModel = new NewCommentViewModel()
    {
        OrderId = orderId,
        OrganisationId = orgId,
        UserId = User.Identity.GetUserId()
    };
    return PartialView(viewModel);
}

[HttpPost]
public ActionResult CreateComment(NewCommentViewModel viewModel)
{
    orderManager.AddComment(viewModel);
    return RedirectToAction("Details", new { id = viewModel.OrderId });
    //return Redirect($"/Order/Details/{viewModel.OrderId}");
}

@{Html.RenderAction("CreateComment", ...);} may be calling your overload.

Try renaming:

public PartialViewResult _CreateComment(int orderId, int orgId)
{
    var viewModel = new NewCommentViewModel()
    {
        OrderId = orderId,
        OrganisationId = orgId,
        UserId = User.Identity.GetUserId()
    };
    return PartialView(viewModel);
}

And calling:

@{Html.RenderAction("_CreateComment", ...);}

First, try to set BeginForm in partial view form to include controller & action method name with POST HTTP method like this:

@using (Html.BeginForm("CreateComment", "Order", FormMethod.Post))
{
    // view controls
} 

Also try assigning GET action method with different name than POST action method name and include ChildActionOnlyAttribute like this:

[ChildActionOnly]
public ActionResult RenderCreateComment(int orderId, int orgId)
{
    var viewModel = new NewCommentViewModel()
    {
        OrderId = orderId,
        OrganisationId = orgId,
        UserId = User.Identity.GetUserId()
    };
    return PartialView(viewModel);
}

And then assign the renamed action in RenderAction :

@{Html.RenderAction("RenderCreateComment", "Order", new { ... });}

Note that a child action supposed to populate or getting data, it shouldn't attempting to update something else.

Similar issues:

Child actions are not allowed to perform redirect actions

Child actions are not allowed to perform redirect actions MVC4

The issue is that you form is generated as a partial from a child action and is you inspect the html for the <form> element you will see that it generated action="/order/details/14" whereas it need to be action="/order/CreateComment"

You need to change the BeginForm() method to generate the correct attribute so it POST to the correct method. In your CreateComment.cshtml view

@model Web.Models.NewCommentViewModel
@using (Html.BeginForm("CreateComment", "Order")) // change
{
    @Html.AntiForgeryToken()
    ....

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM