@Html.PropertyFor cant be used if model utilizes a controller?



Im trying to use the @Html.PropertyFor inside a block.. however.. for some reason I keep getting the following error:

"The model item passed into the dictionary is of type 'System.String', but this dictionary requires a model item of type 'XXXXSite.Definitions.Models.Blocks.XXXXBlock'."

This is my entire view:

@model XXXXBlock

@Html.PropertyFor(p => p.NoCasesFound)

if I open up the "Watch" and types Model.NoCasesFound, then it works just fine and I can see my string that I have entered in EPiServer..

Any ideas why PropertyFor fails?

My model inherits from BlockData and the property is set as virtual and public (public virtual string NoCasesFound { get; set; })


I tried to remove my controller for XXXXBlock (XXXXBlockController), and for some reason @Html.Property started to work? Is this the expected behaviour? That we cant use Html.PropertyFor once the model passes through a controller?

Edited, Jun 29, 2018 14:52

This is how it works:

  1. If you don't have a controller, episerver will try to find a matching view for your block that accepts the XXXXBlock. If you placed your view XXXXBlock.cshtml under Views/Shared/Blocks/ it should find it. Since the model passed in is of type XXXXBlock (or actually an inherited class of this...that's why your properties need to be public and virtual) the above view will work.
  2. If you want to add more logic you need to add a controller. So far so good. In that case you should also create a new class to contain the data to present in your view. A view model. In alloy demo site you can see an example of this in the ContactBlock. The interesting index method looks like this:
        public override ActionResult Index(ContactBlock currentBlock)
            ContactPage contactPage = null;
                contactPage = _contentLoader.Get<ContactPage>(currentBlock.ContactPageLink);

            var linkUrl = GetLinkUrl(currentBlock);
            var model = new ContactBlockModel
                    Heading = currentBlock.Heading,
                    Image = currentBlock.Image,
                    ContactPage = contactPage,
                    LinkUrl = GetLinkUrl(currentBlock),
                    LinkText = currentBlock.LinkText,
                    ShowLink = linkUrl != null

            //As we're using a separate view model with different property names than the content object
            //we connect the view models properties with the content objects so that they can be edited.
            ViewData.GetEditHints<ContactBlockModel, ContactBlock>()
                .AddConnection(x => x.Heading, x => x.Heading)
                .AddConnection(x => x.Image, x => x.Image)
                .AddConnection(x => (object) x.ContactPage, x => (object) x.ContactPageLink)
                .AddConnection(x => x.LinkText, x => x.LinkText);

            return PartialView(model);

So you can see that the model class (ContactBlock) is transformed to a view model class called "ContactBlockModel". After this we also need to tell Episerver about how we mapped these two by using the ViewData.GetEditHings. If you don't do this, you'll lose the major purpose of PropertyFor which is to get support for editors and on page editing. 

3. You need to change the view file to accept your new view model class. In the contact block above that means accepting ContactBlockModel instead like:

@model ContactBlockModel

@Html.PropertyFor(x => x.Image)

This file is also normally moved and renamed to /Views/ContactBlock/Index.cshtml now that is has a proper controller and can have multiple actions. 

Hope that helps to explain things. So go without a controller for simple views and if you want more advanced stuff, go with controller + view model and don't forget to map properties + change type of model in view + rename/move

Edited, Jun 29, 2018 16:16
* You are NOT allowed to include any hyperlinks in the post because your account hasn't associated to your company. User profile should be updated.