1

I'm new to MVC. Trying to load a partial view but get a 500 error in browser console.

After clicking on submit, the action method is triggered and the code is executed without any errors.

I would like to replace the content of myform with a partial view, but there is an error in the browser console.

Do I need to configure any routes. If so, please tell me what/how it should be.

Using Sitecore 8.0.

main.cshtml

<div id="myform">
 @using (Ajax.BeginForm("ResetPassword", "Member", new AjaxOptions { UpdateTargetId = "myform", InsertionMode = InsertionMode.Replace }))
 {
    .....
    <input type="submit" value="Submit"/>
 }
</div>

controller

[HttpPost]        
public ActionResult ResetPassword()
{
  ....
  return PartialView("~/Views/success.cshtml");
}

success.cshtml

@
{
 var contextItem = Sitecore.Context.Item;
}
<div>
  <h3>Your password has been updated.</h3>
  <p>@contextItem.Fields[<id>].Value</p>
</div>

Error:

POST http://mysite.org/api/sitecore/Member/ResetPassword 500 (Internal Server Error)

Stack Trace

> 25812 19:45:17 ERROR Application error. Exception:
> System.Web.HttpUnhandledException Message: An unhandled exception
> occurred. Source: Sitecore.Mvc    at
> Sitecore.Mvc.Pipelines.MvcEvents.Exception.ShowAspNetErrorMessage.ShowErrorMessage(ExceptionContext
> exceptionContext, ExceptionArgs args)    at
> Sitecore.Mvc.Pipelines.MvcEvents.Exception.ShowAspNetErrorMessage.Process(ExceptionArgs
> args)    at (Object , Object[] )    at
> Sitecore.Pipelines.CorePipeline.Run(PipelineArgs args)    at
> Sitecore.Mvc.Pipelines.PipelineService.RunPipeline[TArgs](String
> pipelineName, TArgs args)    at
> Sitecore.Mvc.Filters.PipelineBasedRequestFilter.OnException(ExceptionContext
> exceptionContext)    at
> System.Web.Mvc.ControllerActionInvoker.InvokeExceptionFilters(ControllerContext
> controllerContext, IList`1 filters, Exception exception)    at
> System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext
> controllerContext, String actionName)    at
> Sitecore.Mvc.Controllers.SitecoreActionInvoker.InvokeAction(ControllerContext
> controllerContext, String actionName)    at
> System.Web.Mvc.Controller.<>c__DisplayClass22.<BeginExecuteCore>b__1e()
> at System.Web.Mvc.Async.AsyncResultWrapper.<.cctor>b__0(IAsyncResult
> asyncResult, Action action)    at
> System.Web.Mvc.Controller.EndExecuteCore(IAsyncResult asyncResult)   
> at
> System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncVoid`1.CallEndDelegate(IAsyncResult
> asyncResult)    at System.Web.Mvc.Controller.EndExecute(IAsyncResult
> asyncResult)    at
> System.Web.Mvc.MvcHandler.<BeginProcessRequest>b__5(IAsyncResult
> asyncResult, ProcessRequestState innerState)    at
> System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncVoid`1.CallEndDelegate(IAsyncResult
> asyncResult)    at
> System.Web.Mvc.MvcHandler.EndProcessRequest(IAsyncResult asyncResult) 
> at
> Sitecore.Mvc.Routing.RouteHttpHandler.EndProcessRequest(IAsyncResult
> result)    at
> System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
> at System.Web.HttpApplication.ExecuteStep(IExecutionStep step,
> Boolean& completedSynchronously)
> 
> Nested Exception
> 
> Exception: System.NullReferenceException Message: Object reference not
> set to an instance of an object. Source: App_Web_fel0uk2b    at
> ASP._Page_Views_ResetPassword_cshtml.Execute() in
> c:\inetpub\wwwroot\mysite.org\Website\Views\ResetPassword.cshtml:line
> 7    at System.Web.WebPages.WebPageBase.ExecutePageHierarchy()    at
> System.Web.Mvc.WebViewPage.ExecutePageHierarchy()    at
> System.Web.WebPages.WebPageBase.ExecutePageHierarchy(WebPageContext
> pageContext, TextWriter writer, WebPageRenderingBase startPage)    at
> System.Web.Mvc.ViewResultBase.ExecuteResult(ControllerContext context)
> at
> System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilterRecursive(IList`1
> filters, Int32 filterIndex, ResultExecutingContext preContext,
> ControllerContext controllerContext, ActionResult actionResult)    at
> System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilterRecursive(IList`1
> filters, Int32 filterIndex, ResultExecutingContext preContext,
> ControllerContext controllerContext, ActionResult actionResult)    at
> System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilterRecursive(IList`1
> filters, Int32 filterIndex, ResultExecutingContext preContext,
> ControllerContext controllerContext, ActionResult actionResult)    at
> System.Web.Mvc.ControllerActionInvoker.InvokeActionResultWithFilters(ControllerContext
> controllerContext, IList`1 filters, ActionResult actionResult)    at
> System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext
> controllerContext, String actionName)
  • Can you please provide the stacktrace – Hishaam Namooya Feb 21 '17 at 14:14
  • @HishaamNamooya I just did. Please check – Qwerty Feb 21 '17 at 14:21
  • Can you please provide the Execute method code please since the error is occurring in this which seems to be triggered from line 7 in the ResetPassword.cshtml – Hishaam Namooya Feb 21 '17 at 14:31
  • I have updated my question. The issue is with the variable contextItem in the partial view which is null. Is this by default, that in partial views, we cannot get the Sitecore Context Item? If so, then I have to create an exclusive model for this partial view. – Qwerty Feb 21 '17 at 14:47
2

You can't submit an MVC form in the standard MVC way when using Sitecore. You have to do some specific things.

Method 1: Sitecore().FormHandler

First, your razor view needs to change from using Ajax.BeginForm to Html.BeginRouteForm and then passing in the Sitecore route name. Like this:

@using (Html.BeginRouteForm(Sitecore.Mvc.Configuration.MvcSettings.SitecoreRouteName, FormMethod.Post))
{       
    @Html.Sitecore().FormHandler("Member", "ResetPassword") 

    <input type="submit" />
}

Also note the FormHandler addition. That specifies the controller and action used when submitting the form.

With this method, you can redirect to another page after submission. But can't return a view or partial view.

Method 2: Pure MVC

There is another option that uses pure MVC to submit the form. In this option you would create your form cshtml like this:

@using (Html.BeginForm())
{
    <input type="hidden" name="fhController" value="Member"/>
    <input type="hidden" name="fhAction" value="ResetPassword"/>

    <input type="submit" value="submit"/> 
}

Notice that here we have put the controller and action into hidden fields that will be submitted. This is because on a submit, Sitecore will hit all the controllers that are renderings on the page.

To find the correct POST action. We can use an attribute on the form handler action.

public class ValidateFormHandler : ActionMethodSelectorAttribute
{
    public override bool IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo)
    {
        var controller = controllerContext.HttpContext.Request.Form["fhController"];
        var action = controllerContext.HttpContext.Request.Form["fhAction"];

        return !string.IsNullOrWhiteSpace(controller)
                && !string.IsNullOrWhiteSpace(action)
                && controller == controllerContext.Controller.GetType().Name
                && methodInfo.Name == action;
    }
}

Then add the attribute to your post action:

[HttpPost]
[ValidateFormHandler]
public ActionResult ResetPassword(FormModel model)
{
    // code
}

Method 3: Roll your own Ajax call

Finally - as it looks like you want to make this an ajax request, you could just register your controller action as a route to be used by a $.ajax call.

Add a pipeline process to the Initialize pipeline that will register your route:

public class RegisterRoutes
{
    public virtual void Process(PipelineArgs args)
    {
        RouteTable.Routes.MapRoute("ResetPassword", "Member/ResetPassword", 
            new { controller = "Member", action = "ResetPassword" });
    }
}

Now you can make an ajax post from JavaScript to the url /member/resetpassword and handle the response to update your screen.

Credits for options 1 & 2 to Martina & Kevin:

| improve this answer | |
  • Thank you. Two Questions. (1) In my Ajax.BeginForm(), I have mentioned the controller & action names. Will this still hit all controllers. (2) All the above methods are standards for making a post in Sitecore and not loading a partial view. So, seems we cannot load a partial view like in MVC..is this right – Qwerty Feb 21 '17 at 15:28
  • You should be able to use the Ajax.BeginForm like the Html.BeginForm - but you will want to use the AjaxOptions and give it an OnSuccess function to call when it has finished. Then handle the display that way. It wont just load in a partial view. Have a look at this for an example: blackbeltcoder.com/Articles/script/… – Richard Seal Feb 21 '17 at 15:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.