Exception when trying to preview/inline edit block content (MVC)

 

Hi there,

Working on an EPiServer 7 project to explore EPiServer 7 with MVC.  I have pulled across the EditorialBlock type (from Alloy) and created and MVC controllor and view.  However I am getting an exception when trying to preview the block or edit it inline:

Server Error in '/' Application.


Content with id '5_5' is of type 'Castle.Proxies.EditorialBlockProxy' which does not inherit required type 'EPiServer.Core.PageData'

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: EPiServer.Core.TypeMismatchException: Content with id '5_5' is of type 'Castle.Proxies.EditorialBlockProxy' which does not inherit required type 'EPiServer.Core.PageData'

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: 

[TypeMismatchException: Content with id '5_5' is of type 'Castle.Proxies.EditorialBlockProxy' which does not inherit required type 'EPiServer.Core.PageData']
   EPiServer.DataFactory.ThrowTypeMismatchException(ContentReference link, Type actual, Type required) +193
   EPiServer.DataFactory.Get(ContentReference contentLink, ILanguageSelector languageSelector) +630
   EPiServer.PageBase.GetPage(PageReference pageLink, ILanguageSelector selector) +159
   EPiServer.Web.PageExtensions.LoadCurrentPage.get_CurrentPage() +205
   EPiServer.PageBase.get_CurrentPage() +51
   EPiServer.PageBase.SetCachePolicy() +191
   EPiServer.PageBase.OnInit(EventArgs e) +58
   System.Web.UI.Control.InitRecursive(Control namingContainer) +134
   System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +489

Code snippets:

Block:

[ContentType(
GUID = "5a1ada5d-a6e3-4d8f-a201-8d4b4c40e4a9",
GroupName = SystemTabNames.Content)]
public class EditorialBlock : SiteBlockData
{
  /// <summary>
  /// Content area to edit
  /// </summary>
  [Display(GroupName = SystemTabNames.Content)]
  [CultureSpecific]
  public virtual XhtmlString MainBody { get; set; }
}

Controllor:

public class EditorialBlockController : BlockController<EditorialBlock>
{
  public override ActionResult Index(EditorialBlock currentBlock)
  {
    return PartialView(currentBlock);
  }
}

The view is placed under the 'Views' folder, in a folder called 'EditorialBlock' and is called Index.cshtml.

Any ideas as to the cause of the error?

Many thanks,

Wayne

View:

@model EPiServer7Base.Models.Blocks.EditorialBlock

<div>
  @Html.PropertyFor(m => m.MainBody)
</div>

#64223 Dec 13, 2012 13:56
  • Marija Jemuovic
    Member since: 2010
     

    Perhaps you need to move it to Views/Shared?

    #64228 Dec 13, 2012 16:03
  •  

    No, EPiServer can't find the view if I move it under Shared.

    #64230 Dec 13, 2012 16:14
  •  

    Okay, after more digging it looks like I need to define a Preview Controller for blocks.  I can't find much reference for this, other than a class declaration in: http://world.episerver.com/Blogs/Johan-Bjornfot/Dates1/2012/9/EPiServer-7--Rendering-of-content/ and no examples of a controller.

    What is the purpose of this controller?  What does it need to do differently than the main block controller?  Do I need one for each block type or can I use a generic one for all blocks?  If so how does it know which block view to render?

    I would appreciate more information about this subject!

    Manyt thanks,

    Wayne

    #64234 Dec 13, 2012 17:50
  • Duong Nguyen
    Member since: 2010
     

    Blocks must be hosted in a page, even on preview. The PreviewBlockController provides that host. You need only one for the entire system.

    For the simplest use, you just render the block (Model) which is being hosted using the Html extension method RenderContentData.

     

     

     

     

     

    #64235 Edited, Dec 13, 2012 20:21
  •  

    How should the view be implemented for this controller?  If I try and pass the Model to RenderContentData then I get compilation errors.  I don't quite understand how this controllor and view can be used to preview any block type, when each block type has a separate controller and view (or views) which define how a block is rendered on the website (i.e. how it previews).

    #64281 Edited, Dec 17, 2012 10:18
  • Duong Nguyen
    Member since: 2010
     

    Wayne, this is how the preview index view looks like:

    <%@ Page Title="" Language="C#" Inherits="System.Web.Mvc.ViewPage<EPiServer.Core.IContent>" %>
    <%@ Import Namespace="EPiServer.Web.Mvc.Html" %>

    <%Html.RenderContentData(Model, false);%>

    The block's controller and view will be used by RenderContentData method. The secret here is the "preview" tag. When you request a block in edit mode, it will find the first controller tagged as "preview" to host the block.

    #64289 Dec 17, 2012 12:18
  •  

    Many thanks Duong.  I am definitely getting closer!  I am getting an exception though:

    Compilation Error

    Description: An error occurred during the compilation of a resource required to service this request. Please review the following specific error details and modify your source code appropriately. 

    Compiler Error Message: CS0115: 'ASP._Page_Views_PreviewBlock_index_cshtml.Execute()': no suitable method found to override

    Source Error:

     
    Line 46:         }
    Line 47:         
    Line 48:         public override void Execute() {
    Line 49: BeginContext("~/Views/PreviewBlock/index.cshtml", 91, 2, true);
    Line 50: 

    Here is my view:

    @inherits System.Web.Mvc.ViewPage<EPiServer.Core.IContent>
    @using EPiServer.Web.Mvc.Html

    @Html.RenderContentData(Model, false)

    My controller is just the default implementation - I suspect it is missing something:

    [TemplateDescriptor(Inherited = true, Tags = new string[] { RenderingTags.Preview })]
    public class PreviewBlockController : ActionControllerBase, IRenderTemplate<IContentData>
    {
    //
    // GET: /PreviewBlock/
    public ActionResult Index()
    {
    return View();
    }

    }

     

    #64291 Dec 17, 2012 12:31
  • Duong Nguyen
    Member since: 2010
     

    Hmm, it sounds like you have some missing configuration of Razor view engine. Have a look at this and hope it helps: http://stackoverflow.com/questions/4808640/mvc3-razor-cshtml-execute-no-suitable-method-found-to-override

    #64295 Dec 17, 2012 13:07
  •  

    Many thanks for the help. Still no joy I'm afraid.  The configuration changes in the article you referenced did not resolve the error, nor did the other advice listed.  The actual project template I used was the Visual Studio EPiServer MVC project template, so I would hope the base configuration is correct.

    It is frustrating that there are no examples of an MVC EPiServer 7 site.  Given that EPiServer pulled the MVC Alloy site before release, I wonder if building EPiServer websites with MVC is not quite there yet.

    #64297 Dec 17, 2012 13:21
  • Marija Jemuovic
    Member since: 2010
     

    Hi, guys,

    I followed the instructions on the stackoverflow link Duong has sent, particularily: 

    "That config section is technically correct, but you don't need it in your root web.config. Keep it in ~/Views/Web.config, but just make sure your pageBaseType = "System.Web.Mvc.WebViewPage", instead of "System.Web.Mvc.ViewPage". I just resolved this same error in my application with that minor change."

    This is how my view looks like (I don't want to render layout page):

    @using EPiServer.Web.Mvc.Html
    @inherits System.Web.Mvc.WebViewPage<EPiServer.Core.IContent>
    
    @{
        Layout = null;
    }
    
    @if(@Model != null) {
        { Html.RenderContentData(@Model, false); }
    }

    However, I also needed to make a change in the Controller, because the model was always null:

        [TemplateDescriptor(Inherited = true, Tags = new string[] { RenderingTags.Preview })]
        public class PreviewBlockController : ActionControllerBase, IRenderTemplate<IContentData>
        {
            public ActionResult Index()
            {
                var contentLink = Request.RequestContext.GetContentLink();
                IContent content = null;
                if (contentLink != null)
                {
                    var contentRepo = ServiceLocator.Current.GetInstance<IContentRepository>();
                    content = contentRepo.Get<IContent>(contentLink);
                }
    
                return View(content);
            }
        }

     

    Now, I get the expected view.

        

    #64509 Edited, Dec 24, 2012 10:47
  •  

    That did the trick.

    Many thanks!

    #64820 Jan 10, 2013 16:13
  • Marija Jemuovic
    Member since: 2010
     

    Please also check this post, there are updates to the controller and view code above:

    http://world.episerver.com/Modules/Forum/Pages/Thread.aspx?id=64774&epslanguage=en

    #64832 Jan 11, 2013 9:13