“Cannot create an instance of an Interface” (an MvC 3 Wizard inside Orchard CMS)

asp.net-mvc-3orchardcms

Based on the great answer at multi-step registration process issues in asp.net mvc (splitted viewmodels, single model), I used the example Darin Dimitrov provided to test out an ASP.net MVC3 wizard. It works standalone, but not inside Orchard CMS v1.3.

I am getting the following error:


Server Error in '/' Application.

Cannot create an instance of an interface.

Description: An unhandled exception occurred during the execution of
the current web request. Please review the stack trace for more
information about the error and where it originated in the code.

Exception Details: System.MissingMethodException: Cannot create an
instance of an interface.

Source Error:

An unhandled exception was generated during the execution of the
current web request. Information regarding the origin and location of
the exception can be identified using the exception stack trace below.

Stack Trace:

[MissingMethodException: Cannot create an instance of an interface.]
System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean
publicOnly, Boolean noCheck, Boolean& canBeCached,
RuntimeMethodHandleInternal& ctor, Boolean& bNeedSecurityCheck) +0
System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean
skipCheckThis, Boolean fillCache) +98
System.RuntimeType.CreateInstanceDefaultCtor(Boolean publicOnly,
Boolean skipVisibilityChecks, Boolean skipCheckThis, Boolean
fillCache) +241 System.Activator.CreateInstance(Type type, Boolean
nonPublic) +69
System.Web.Mvc.DefaultModelBinder.CreateModel(ControllerContext
controllerContext, ModelBindingContext bindingContext, Type modelType)
+199 System.Web.Mvc.DefaultModelBinder.BindComplexModel(ControllerContext
controllerContext, ModelBindingContext bindingContext) +572
System.Web.Mvc.DefaultModelBinder.BindModel(ControllerContext
controllerContext, ModelBindingContext bindingContext) +449
System.Web.Mvc.ControllerActionInvoker.GetParameterValue(ControllerContext
controllerContext, ParameterDescriptor parameterDescriptor) +317
System.Web.Mvc.ControllerActionInvoker.GetParameterValues(ControllerContext
controllerContext, ActionDescriptor actionDescriptor) +117
System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext
controllerContext, String actionName) +343
System.Web.Mvc.Controller.ExecuteCore() +116
System.Web.Mvc.ControllerBase.Execute(RequestContext requestContext)
+97 System.Web.Mvc.ControllerBase.System.Web.Mvc.IController.Execute(RequestContext
requestContext) +10
System.Web.Mvc.<>c__DisplayClassb.b__5() +37
System.Web.Mvc.Async.<>c__DisplayClass1.b__0() +21
System.Web.Mvc.Async.<>c__DisplayClass81.<BeginSynchronous>b__7(IAsyncResult
_) +12 System.Web.Mvc.Async.WrappedAsyncResult
1.End() +62 System.Web.Mvc.<>c__DisplayClasse.b__d() +50
System.Web.Mvc.SecurityUtil.b__0(Action f) +7
System.Web.Mvc.SecurityUtil.ProcessInApplicationTrust(Action action)
+22 System.Web.Mvc.MvcHandler.EndProcessRequest(IAsyncResult asyncResult) +60
System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.EndProcessRequest(IAsyncResult
result) +9
Orchard.Mvc.Routes.HttpAsyncHandler.EndProcessRequest(IAsyncResult
result) in
d:\Builds\OrchardFull\src\Orchard\Mvc\Routes\ShellRoute.cs:148
System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
+8963149 System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +184

Version Information: Microsoft .NET Framework Version:4.0.30319;
ASP.NET Version:4.0.30319.237


I am venturing a guess that it's the controller that's causing a fuss. Here is the code:

[Themed]
    public class WizardController : Controller
    {
        public ActionResult Index()
        {
            var wizard = new WizardViewModel();
            wizard.Initialize();
            return View(wizard);
        }

        [HttpPost]
        public ActionResult Index([Deserialize] WizardViewModel wizard, IStepViewModel step)
        {
            wizard.Steps[wizard.CurrentStepIndex] = step;
            if (ModelState.IsValid)
            {
                if (!string.IsNullOrEmpty(Request["next"]))
                {
                    wizard.CurrentStepIndex++;
                }
                else if (!string.IsNullOrEmpty(Request["prev"]))
                {
                    wizard.CurrentStepIndex--;
                }
                else
                {
                    // TODO: we have finished: all the step partial
                    // view models have passed validation => map them
                    // back to the domain model and do some processing with
                    // the results

                    return Content("thanks for filling this form", "text/plain");
                }
            }
            else if (!string.IsNullOrEmpty(Request["prev"]))
            {
                // Even if validation failed we allow the user to
                // navigate to previous steps
                wizard.CurrentStepIndex--;
            }
            return View(wizard);
        }
    }

But I am not 100% sure, and the other culprit could be the WizardViewModel:

[Serializable]
public class WizardViewModel
{
    public int CurrentStepIndex { get; set; }
    public IList<IStepViewModel> Steps { get; set; }

    public void Initialize()
    {
        Steps = new IStepViewModel[]
        {
            new Step1ViewModel(),
            new Step2ViewModel(),
            new Step3ViewModel()
        };
    }
}

That last part is a manual insertion of the steps and alters the code originally posted (direct from author). Any help is greatly appreciated.

Best Answer

Apparently, the Model Binder you are using can't find the model it needs to instantiate from the supplied interface (IStepViewModel)

I am quite sure that the default ASP.NET MVC ModelBinder can't do such thing, as it would require some custom logic to choose the concrete interface implementation that should be instantiated.

Therefore, you have two solutions:

  1. Check your sample, I think it provides a custom ModelBinder, and register it in Orchard by implementing an IModelBinderProvider
  2. Don't ask for a IStepViewModel in the Index action:

    public ActionResult Index([Deserialize] WizardViewModel wizard, IStepViewModel step)
    

    And replace it with a concrete class.

Related Topic