Well you're in luck because I wrote a TON of code to do something similar.  This also takes into account if you want to return the model as a JSON object or a View.  It also wraps all the Ajax calls into a wrapper response element
Basically if you have a UI guy doing stuff, you NEVER need to know what he wants.  Let him write the views, or make AJAX calls.  This completely decouples the UI person from the C# developer (as long as he understands how to write MVC Views, he doesn't need to know at all how the controller works, just the model being passed).
The ControllerBase class:
public abstract class MyControllerBase : Controller
{
    // could be moved to web.config
    private const _jsonDataType = "JsonDataType";
    public bool IsAjaxRequest
    {
        get
        {
            return this.HttpContext.Request.IsAjaxRequest();
        }
    }
    public bool IsAjaxHtmlRequest
    {
        get
        {
            return string.Equals(this.Request.Headers[MyControllerBase._jsonDataType], "html", StringComparison.CurrentCultureIgnoreCase);
        }
    }
    private JsonResponse GetAjaxResponse()
    {
        JsonResponse result = new JsonResponse();
        result.IsValid = true;
        return result;
    }
    private JsonResponse<T> GetAjaxResponse<T>(T model)
    {
        JsonResponse<T> result = new JsonResponse<T>();
        result.Data = model;
        result.IsValid = true;
        return result;
    }
    private JsonResponse<string> GetAjaxHtmlResponse()
    {
        JsonResponse<string> result = new JsonResponse<string>();
        result.Data = this.PartialViewToString(this.ControllerContext.RouteData.Values["Action"].ToString(), null);
        result.IsValid = true;
        return result;
    }
    private JsonResponse<string> GetAjaxHtmlResponse<T>(T model)
    {
        JsonResponse<string> result = new JsonResponse<string>();
        result.Data = this.PartialViewToString(this.ControllerContext.RouteData.Values["Action"].ToString(), model);
        result.IsValid = true;
        return result;
    }
    private JsonResponse<string> GetAjaxHtmlResponse<T>(T model, string viewName)
    {
        JsonResponse<string> result = new JsonResponse<string>();
        result.Data = this.PartialViewToString(viewName, model);
        result.IsValid = true;
        return result;
    }
    public ActionResult ViewOrAjax()
    {
        return this.ViewOrAjax(JsonRequestBehavior.DenyGet);
    }
    public ActionResult ViewOrAjax(JsonRequestBehavior jsonRequestBehavior)
    {
        if (this.ControllerContext.IsChildAction)
        {
            return this.PartialView(this.ControllerContext.RouteData.Values["Action"].ToString(), null);
        }
        if (this.IsAjaxRequest)
        {
            if (this.IsAjaxHtmlRequest)
            {
                return this.Json(this.GetAjaxHtmlResponse(), jsonRequestBehavior);
            }
            return this.Json(this.GetAjaxResponse(), jsonRequestBehavior);
        }
        return this.View(this.ControllerContext.RouteData.Values["Action"].ToString(), null);
    }
    public ActionResult ViewOrAjax<T>(T model)
    {
        return this.ViewOrAjax<T>(model, JsonRequestBehavior.DenyGet);
    }
    public ActionResult ViewOrAjax<T>(T model, JsonRequestBehavior jsonRequestBehavior)
    {
        if (this.ControllerContext.IsChildAction)
        {
            return this.PartialView(model);
        }
        if (this.IsAjaxRequest)
        {
            if (this.IsAjaxHtmlRequest)
            {
                return this.Json(this.GetAjaxHtmlResponse(model), jsonRequestBehavior);
            }
            return this.Json(this.GetAjaxResponse<T>(model), jsonRequestBehavior);
        }
        return this.View(model);
    }
    public ActionResult ViewOrAjax<T>(IView view, T model, JsonRequestBehavior jsonRequestBehavior)
    {
        if (this.ControllerContext.IsChildAction)
        {
            return this.PartialView(model);
        }
        if (this.IsAjaxRequest)
        {
            if (this.IsAjaxHtmlRequest)
            {
                return this.Json(this.GetAjaxHtmlResponse(model), jsonRequestBehavior);
            }
            return this.Json(this.GetAjaxResponse<T>(model), jsonRequestBehavior);
        }
        return this.View(view, model);
    }
    public ActionResult ViewOrAjax<T>(string viewName, T model)
    {
        return this.ViewOrAjax<T>(viewName, model, JsonRequestBehavior.DenyGet);
    }
    public ActionResult ViewOrAjax<T>(string viewName, T model, JsonRequestBehavior jsonRequestBehavior)
    {
        if (this.ControllerContext.IsChildAction)
        {
            return this.PartialView(model);
        }
        if (this.IsAjaxRequest)
        {
            if (this.IsAjaxHtmlRequest)
            {
                return this.Json(this.GetAjaxHtmlResponse(model, viewName), jsonRequestBehavior);
            }
            return this.Json(this.GetAjaxResponse<T>(model), jsonRequestBehavior);
        }
        return this.View(viewName, model);
    }
    public ActionResult ViewOrAjax<T>(string viewName, string masterName, T model)
    {
        return this.ViewOrAjax<T>(viewName, masterName, model, JsonRequestBehavior.DenyGet);
    }
    public ActionResult ViewOrAjax<T>(string viewName, string masterName, T model, JsonRequestBehavior jsonRequestBehavior)
    {
        if (this.ControllerContext.IsChildAction)
        {
            return this.PartialView(model);
        }
        if (this.IsAjaxRequest)
        {
            if (this.IsAjaxHtmlRequest)
            {
                return this.Json(this.GetAjaxHtmlResponse(model, viewName), jsonRequestBehavior);
            }
            return this.Json(this.GetAjaxResponse(model), jsonRequestBehavior);
        }
        return this.View(viewName, masterName, model);
    }
    protected internal new ViewResult View(string viewName, string masterName, object model)
    {
        if (model != null)
        {
            ViewData.Model = model;
        }
        ViewResult result = new ViewResult
        {
            ViewName = viewName,
            MasterName = masterName,
            ViewData = ViewData,
            TempData = TempData
        };
        return result;
    }
}
The JsonResponse<> global wrapper for Ajax Calls:
public class JsonResponse
{
    public JsonResponse()
    {
    }
    public bool IsValid { get; set; }
    public bool IsAjaxRequestUnsupported { get; set; }
    public string RedirectTo { get; set; }
    public string CanonicalUrl { get; set; }
}
public class JsonResponse<T> : JsonResponse
{
    public JsonResponse() : base()
    {
    }
    public T Data { get; set; }
}
The Javascript global_getJsonResponse code (require jQuery):
function global_getJsonResult(Controller, View, data, successCallback, completeCallback, methodType, returnType, jsonDataType) {
    if (IsString(Controller)
        && IsString(View)
        && !IsUndefinedOrNull(data)) {
        var ajaxData;
        var ajaxType;
        if (typeof (data) == "string") {
            ajaxData = data;
            ajaxType = "application/x-www-form-urlencoded"
        }
        else {
            ajaxData = JSON.stringify(data);
            ajaxType = "application/json; charset=utf-8";
        }
        var method = 'POST';
        if (methodType) {
            method = methodType;
        }
        var dataType = 'json';
        if (returnType) {
            dataType = returnType;
        }
        var jsonType = 'html';
        if (jsonDataType) {
            jsonType = jsonDataType;
        }
        var jqXHR = $.ajax({
            url: '/' + Controller + '/' + View,
            headers: { JsonDataType: jsonType },
            data: ajaxData,
            type: method,
            dataType: dataType,
            contentType: ajaxType,
            success: function (jsonResult) {
                if (!IsUndefinedOrNull(jsonResult)
                    && jsonResult.hasOwnProperty("RedirectTo")
                    && !IsUndefinedOrNull(jsonResult.RedirectTo)
                    && jsonResult.RedirectTo.length > 0) {
                    $.fn.notify('error', 'Login Expired', 'You have been inactive for a prolonged period of time, and have been logged out of the system.');
                    window.setTimeout(function () { window.location = jsonResult.RedirectTo }, 5000);
                }
                else if (IsFunction(successCallback)) {
                    successCallback(jsonResult, Controller + '/' + View);
                }
            },
            error: function (jqXHR, textStatus, errorThrown) {
                if (errorThrown != 'abort') {
                    $.fn.notify('error', 'Whoops! Something went wrong.', 'We have been notified of the error.'/* textStatus + ': ' + errorThrown*/);
                }
                log('ERROR IN global_getJsonResult() : ', textStatus, errorThrown, jqXHR);
            },
            complete: function (jqXHR, textStatus) {
                if (IsFunction(completeCallback)) {
                    completeCallback(jqXHR, textStatus, Controller + '/' + View);
                }
            }
        });
        return jqXHR;
    }
}
This code supports both server side and client side TimeOuts via Handling session timeout in ajax calls, with a change like:
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
  if (filterContext.HttpContext.Request.IsAjaxRequest())
  {
    filterContext.Result = new JsonResult
    {
      Data = new JsonResponse<bool>
      {
        IsValid = false,
        RedirectTo = FormsAuthentication.LoginUrl
      },
      JsonRequestBehavior = JsonRequestBehavior.AllowGet
    };
  }
  else
  {
    base.HandleUnauthorizedRequest(filterContext);
  }
}
A couple of Extension Methods on controller to allow you to return rendered partial views as text in json (this code was from SO, I usually document such but I lost it):
internal static class ControllerExtensions
{
  public static string PartialViewToString(this Controller instance, object model)
  {
    string viewName = instance.ControllerContext.RouteData.GetRequiredString("action");
    return ControllerExtensions.PartialViewToString(instance, viewName, model);
  }
  public static string PartialViewToString(this Controller instance, string viewName, object model)
  {
    string result;
    ViewDataDictionary viewData = instance.ViewData;
    viewData.Model = model;
    using (var sw = new StringWriter())
    {
      var viewResult = ViewEngines.Engines.FindPartialView(instance.ControllerContext, viewName);
      var viewContext = new ViewContext(instance.ControllerContext, viewResult.View, viewData, instance.TempData, sw);
      viewResult.View.Render(viewContext, sw);
      viewResult.ViewEngine.ReleaseView(instance.ControllerContext, viewResult.View);
      result = sw.GetStringBuilder().ToString();
}
    return result;
  }
}
Now derive (sadly) all your controllers from this base controller:
public HomeController : MyBaseController
{
  public ActionResult Index()
  {
    var viewModel = new MyViewModel();
    return this.ViewOrAjax(viewModel);
  }
}
Now if the page is called by the browser as your standard get, you get the page rendered normally with a Layout (aka this.View(viewModel)).
If you call it using Ajax via the Javascript:
global_getJsonResult("Home",  // Controller or 'Area/Home' for areas
  "Index",                    // View
  $('#form').serialize(),     // Json object or a serialized Form
  jsCallBack,                 // call back function or null
  "Post",                     // Get or Post
  "Html");                    // "Html" to return a Partial View in "Data" 
                              // or "Json" to return a serialized view model in "Data"