Reputation: 35
I have one normal view (NV) and 2 partial views (PV1 and PV2), PV2 is nested in PV1, and PV1 is in NV. The issue i am having is that PV1 and PV2 both have an optional pentameter called "isSuccessful" that is added to the View bag "ViewBag.IsSuccessful = isSuccessful;" in the action, and for some reason when PV1 has its "isSuccessful" set to true PV2's "isSuccessful" is bonded to true as well. This causing PV2 to run some JavaScript functions prematurely causing other issues.
Code (Structure And Example)
in the controller
public ActionResult NV(int id)
{
var model = GetNVModel(id);
return View(model);
}
public ActionResult PV1 (int pv1Id = 0, bool isSuccessful = false)
{
var model = GetPV1Model(id);
ViewBag.IsSuccessful = isSuccessful;
return PartialView(model);
}
public ActionResult PV2 (int pv2Id = 0, bool isSuccessful = false)
{
var model = GetPV2Model(id);
if(model == null){model = new PV2Model();}
ViewBag.IsSuccessful = isSuccessful;
return PartialView(model);
}
The Views
NV.cshtml
@model NVModel
<div>
@if (Model != null && Model.PV1Id != null && Model.PV1Id > 0)
{<text>
@Html.Action("PV1", "ControlerName", new { PV1Id = Model.PV1Id, isSuccessful = true})
</text>}
</div>
PV1.cshtml
@model PV1Model
@{bool isSuccessful = (ViewBag.IsSuccessful != null ? (bool)ViewBag.IsSuccessful : false);}
<div>
@if (Model != null && Model.PV2Id != null && Model.PV2Id > 0)
{<text>
@Html.Action("PV2", "ControlerName", new { PV2Id = Model.PV2Id })
</text>}
</div>
<script>
@if (isSuccessful )
{<text>
function sayHello()
{console.log('Hello PV1');}
</text>}
</script>
PV2.cshtml
@model PV2Model
@{bool isSuccessful = (ViewBag.IsSuccessful != null ? (bool)ViewBag.IsSuccessful : false);}
<div>
@if (Model != null)
{<text>
@Html.TextBoxFor(model=> model.Message)
</text>}
</div>
<script>
@if (isSuccessful )
{<text>
$(document).ready(function(){
console.log($("#Message").val());
});
</text>}
</script>
What I don't understand is why PV1's ViewData/ViewBag Is being passed to PV2. I thought that not passing all of the parent ViewData/ViewBag was part of the point of using "@Html.Action" over "@Html.Partial". What I need to know is if there is a parameter I need to pass in to "@Html.Action" or a web.config attribute needs to be flipped, because the above is not just a one time thing, it is the way i have been doing most of my pages in order to make the views as flexible as possible.
I am using ASP.NET MVC 4, C#, and .NET 4.5
Thanks for any help or clues to this issue.
Upvotes: 1
Views: 634
Reputation: 34992
ViewBag is not shared between the actions, however the route parameters are! You can see this if you set a breakpoint inside the PV2
method and check the ViewBag before executing ViewBag.IsSuccessful = isSuccessful;
. You will see that the ViewBag is empty but the method received the parameter as true.
The problem is that you are passing a route parameter isSuccessful
to PV1 with @Html.Action("PV1", "ControlerName", new { PV1Id = Model.PV1Id, isSuccessful = true})
so when you call the PV2 action the route attributes for PV2 are merged with the current ones. That means isSuccessful will be passed to PV2.
If you check the MVC source code for the Html.Action
helper, you will see that the route attributes are merged with the current ones. Check the internal ActionHelper
method, where the merge is happening:
internal static void ActionHelper(HtmlHelper htmlHelper, string actionName, string controllerName, RouteValueDictionary routeValues, TextWriter textWriter)
{
...
//The route values provided to @Html.Action are merged with the current ones
RouteValueDictionary additionalRouteValues = routeValues;
routeValues = MergeDictionaries(routeValues, htmlHelper.ViewContext.RouteData.Values);
...
}
If you want to prevent this, you can override the route parameter when calling PV2. For this you can do the following:
@Html.Action("PV2", "Home", new { isSuccessful = "" })
You could also call the action using the RouteValueDictionary
which would let you set the route parameter as null:
@Html.Action("PV2", "Home", new RouteValueDictionary{{"isSuccessful", null}})
Upvotes: 1