MVC Ajax Sys is undefined message

I spent an entire day trying to figure out why my Ajax.Begin form helper was failing to update the target div container. By chance I noticed the Sys is undefined message flash past in the Chrome console window. I’ve seen this before with Ajax enabled websites and it usually points to the project not being configured to use Ajax correctly. The jquery.unobtrusive-ajax package has been installed through NuGET correctly but it hadn’t set the configuration correctly.

Make sure the jquery.unobtrusive-ajax.js file is loaded after jquery and <add key=”UnobtrusiveJavaScriptEnabled” value=”true” /> in included in the web.confg <appSettings> section.

Visual Studio Creates an unwanted _ViewStart.cshtml

Many people have noticed Visual Studio sometimes creates an unwanted _ViewStart.cshtml in MVC projects. This happens when a Views is created manually from the Visual Studio right click menu rather than a controller.

The _ViewStart.cshtml file can cause all sorts of unwanted issues, especially when used in conjunction with third party systems such as Sitecore (can cause infinite looping when rendering a view).

To prevent this file being created make sure Use a layout page is unticked or if the view will be used as a partial view tick Create as a partial view.

MVC model binding with helpers

It is possible to bind your HTML controls to a model without the use of helpers such as @Html.TestboxFor()

Take this controller

public class MyControllerController : Controller
{
     public ActionResult Submit()
     {
         return View(new MyViewModel());
     }

     [HttpPost]
     public ActionResult Submit(MyViewModel model)
     {
            // model should be not null, with properties properly initialized from form values
            return View(model);
     }
}

and model

public class MyNestedViewModel
{
    public string AnotherProperty { get; set; }
}

public class MyViewModel
{
    public MyViewModel()
    {
         Nested = new MyNestedViewModel();
    }

    public string SomeProperty { get; set; }

    public MyNestedViewModel Nested  { get; set; }
}

The values can be bound to the model using pure HTML.

<form method="POST" action="MyController/Submit">
    <div><label>Some property</label><input type="text" name="SomeProperty" /></div>
    <div><label>Another property</label><input type="text" name="Nested.AnotherProperty" /></div>
    <button type="submit">Submit</button>
</form>

MVC Adding controls to a form by looping through the model

MVC allows forms to be dynamically created by looping through the view model. By doing this you can add/remove fields in the view model and the form will update to reflect the changes. Adding the below to a Razor form will add each field in the view model using the Editor template. This will ensure the correct control will be used based on the field type


@foreach (var property in ViewData.ModelMetadata.Properties)
{
@Html.Label(property.DisplayName ?? property.PropertyName)
@Html.Editor(property.PropertyName)
}

ASP.net MVC $.ajax performing full post back on button click

One of the biggest mistakes when attaching an html button to an ajax request is not declaring the button type. By default html buttons will submit the entire form, which is not what we want with an ajax request. To prevent this happening make sure button has a type of button e.g.

The following will result in a full post back after executing the AjaxCall JavaScript function.

<button onlick=”AjaxCall()”>Click me</button>

However this will run the AjaxCall JavaScript function but not perform a full post back.

<button type=”button” onlick=”AjaxCall()”>Click me</button>

MVC Creating a Default Error Handler for a Controller

All you have to do to create a default error handler for your ASP.NET MVC controller is put the HandleError attribute on the class. Then, if your code throws an unhandled exception (one not caught in the Try…Catch block), the user will be sent the default Error View in the Views/Shared folder:

<HandleError>
Public Class HomeController Inherits System.Web.Mvc.Controller

At least that’s what the attribute will do if you have this tag inside the system.web element in your web.config file:

<customErrors mode=”On” defaultRedirect=”Error”/>

You can add whatever error information you want to the default Error View by adding code to the View that writes out properties from the Model’s Exception property. Alternatively, setting the customErrors element’s mode to RemoteOnly will, when you’re debugging, let you continue to see ASP.NET’s default error page with all of its information while still sending the Error View to your users in production.

MVC ViewData / ViewBag / TempData / Session

ViewData

1. ViewData is a dictionary object that is derived from ViewDataDictionary class.
2. ViewData is used to pass data from controller to corresponding view.
3. It’s life lies only during the current request.
4. If redirection occurs then it’s value becomes null.
5. It’s required typecasting for getting data and check for null values to avoid error.

ViewBag

1. ViewBag is a dynamic property that takes advantage of the new dynamic features in C# 4.0.
2. Basically it is a wrapper around the ViewData and also used to pass data from controller to corresponding view.
3. It’s life also lies only during the current request.
4. If redirection occurs then it’s value becomes null.
5. It doesn’t required typecasting for getting data.

TempData

1. TempData is a dictionary object that is derived from TempDataDictionary class and stored in short lives session.
2. TempData is used to pass data from current request to subsequent request (means redirecting from one page to another).
3. It’s life is very short and lies only till the target view is fully loaded.
4. It’s required typecasting for getting data and check for null values to avoid error.
5. It is used to store only one time messages like error messages, validation messages. To persist data with TempData refer this article: Persisting Data with TempData

Session

1. Session is also used to pass data within the ASP.NET MVC application and Unlike TempData, it never expires.
2. Session is valid for all requests, not for a single redirect.
3. It’s also required typecasting for getting data and check for null values to avoid error.

MVC HiddenFor not getting correct value from model

When assigning a value to a HiddenFor html helper MVC will always use the first value posted. So if the value is then updated during a post back like below, the browser will still display the original value.

[HttpPost]
public ActionResult Foo(SomeModel model)
{
    model.CurrentStep = Steps.SomeNewValue; // CurrentStep is the HiddenFor value
    return View(model);
}

There are two solutions.

1. Clear the model state for the HiddenFor value before assigning the new value:

[HttpPost]
public ActionResult Foo(SomeModel model)
{
    ModelState.Remove("CurrentStep");
    model.CurrentStep = Steps.SomeNewValue;
    return View(model);
}

2. Manually generate the hidden field

<input type="hidden" name="NextStep" value="<%= Model.CurrentStep %>" />