I've been using a method from a popular SO post found here: How to render an ASP.NET MVC view as a string?
Instead of using the method as an extension method, I placed it on a BaseController, and then all of my controllers inherit the base. Here is my implementation:
public string RenderRazorViewToString(string viewName, object model = null)
{
ViewData.Model = model;
using (var sw = new StringWriter())
{
var viewResult = ViewEngines.Engines.FindPartialView(ControllerContext,
viewName);
var viewContext = new ViewContext(ControllerContext, viewResult.View,
ViewData, TempData, sw);
viewResult.View.Render(viewContext, sw);
viewResult.ViewEngine.ReleaseView(ControllerContext, viewResult.View);
return sw.GetStringBuilder().ToString();
}
}
And it has worked perfectly (I think/hope) until Yesterday.
I have a javascript function that makes an AJAX call to a controller, and provides the parameter "firstName". The controller accepts it, creates a new viewmodel, sets the FirstName property, and then renders the modal (bootstrap3) partial view. The modal uses @Html.EditorFor
to render the FirstName
property of the ViewModel. However, instead of the text displayed being what is set on the controller - the value is the parameter passed by Javascript. In essence, when the parameter of the AJAX GET request matches the property name in a ViewModel (case in-sensitive), the parameter supplied takes precedence. Here's the code I've been testing with:
function testModelBindingTempData() {
var $modalContainer = $('#modalContainer');
$.ajax({
url: "@Url.Action("GetTestModal")",
method: "GET",
data: {
firstName: "Michael is the bees knees."
},
success: function(data) {
$modalContainer.html(data).find('.modal').modal('show');
},
error: function(xhr, status, err) {
parseJsonHeaders(xhr, { notificationLocation: '.notification-section' });
}
});
}
public JsonResult GetTestModal(string firstName)
{
TestModalViewModel vm = new TestModalViewModel();
vm.FirstName = "Michael is okay";
//just render and hope the best
return Json(RenderRazorViewToString("~/Views/Ajax/_TestModal.cshtml", vm));
}
@model Sample.Web.ViewModels.Ajax.TestModalViewModel
<div class="modal modal-primary" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header"><span>Primary Simple Modal</span></div>
<div class="modal-body">
Used to inform the user of important stuff!
@Html.EditorFor(m => m.FirstName)
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
The result: modal displays value supplied from the AJAX call instead of value set in the ViewModel
I discovered the problem value is in the ViewData.ModelState
key-value pair, but I have no idea why THAT value is being set instead of the value set in the controller and the expression in the the HTML helper.
My expectation is that when you set a value in the controller, it should take precedence over a model state value, or any other data available.
Does anyone know why this is happening? Any advice is appreciated, thanks!
/edit: After additional testing, this appears to happen with regular ActionResults/Views too. :/