(Edit: This might not answer your problem at all, I read and wrote it on the bus on my phone and apparently missed a few details)
Had the same problem yesterday. Is your model and view named the same? If that's the case it seems like Episerver ignores the controller and just passes the model to the view as is and the view expects the view model and not just the model. Try renaming the view and load it explicitly in the controller.
As for why this is: Performance is way better if you don't need to go through the entire mvc pipeline. If you just present the model without doing anything in the controller it's faster to just skip the controller entirely.
Hey Danial,
This is what it looks like if you want to take a peak.
public class ConsultantBlockController : BlockController<ConsultantBlock> { private readonly IContentLoader contentLoader; private readonly ContentLocator contentLocator; public ConsultantBlockController(IContentLoader contentLoader, ContentLocator contentLocator) { this.contentLoader = contentLoader; this.contentLocator = contentLocator; } public override ActionResult Index(ConsultantBlock currentBlock) { var model = new ConsultantBlockViewModel(currentBlock); if (currentBlock.ContactConsultantUrl != null) { model.ContactUrl = UrlResolver.Current.GetUrl(new UrlBuilder(currentBlock.ContactConsultantUrl), ContextMode.Default); } return PartialView(model); } }
VIEWMODEL
public class ConsultantBlockViewModel : BlockViewModel<ConsultantBlock> { public ConsultantBlockViewModel(ConsultantBlock currentBlock) : base(currentBlock) { } public string ContactUrl { get; set; } }
MODEL
[SiteContentType(DisplayName = "Consultant Block", GUID = "385ae067-9705-42c2-b8e7-2fb0c87dd833", Description = "Block to contain link buttons and footnote (or partner) images/urls.", Order = 10)] [SiteImageUrl("~/Content/ContentIcons/contact.png")] public class ConsultantBlock : SiteBlockData { [Display(Name = "Visit Playground Url", Description = "Url to point to vap with directions to playground.", GroupName = SystemTabNames.Content, Order = 10)] [CultureSpecific] public virtual Url VisitPlaygroundUrl { get; set; } [Display(Name = "Contact Consultant Url", Description = "Url to point to contact form for consultant.", GroupName = SystemTabNames.Content, Order = 20)] [CultureSpecific] [Required] public virtual Url ContactConsultantUrl { get; set; } [Display(Name = "Footnotes Header", Description = "Optional header for footnotes section of block.", GroupName = SystemTabNames.Content, Order = 30)] [CultureSpecific] [UIHint(UIHint.Textarea)] public virtual string FootnotesHeader { get; set; } [Display(Name = "Footnotes", Description = "Footnotes for consultants. Should use ImageText block.", GroupName = SystemTabNames.Content, Order = 40)] [AllowedTypes(new[] { typeof(TextImageBlock) })] [CultureSpecific] [UIHint(UIHint.Block)] public virtual ContentArea Footnotes { get; set; } [NotMapped] [Ignore] public string VisitPlaygroundButtonUrl { get; set; } }
And when i render the property,
@Html.PropertyForm(x=>x.CurrentBlock.Footnotes) <-- throws the following error.
The model item passed into the dictionary is of type 'Test.Models.ViewModels.ConsultantBlockViewModel', but this dictionary requires a model item of type 'Test.Models.Blocks.Generic.ConsultantBlock'.
Any help would be appreciated.
Just to add on to it. If i loop the content area and do Html.rendercontentdata(icontent,true). then the property for in the nest block now expect the active model which would be consultantblockviewmodel. This event throws the error.
The model item passed into the dictionary is of type 'EPiServer.Core.XhtmlString', but this dictionary requires a model item of type 'Test.Models.ViewModels.ConsultantBlockViewModel'.
Try and rename and move your view template.
Ie.
From: ~/Views/Shared/Blocks/ConsultantBlock.cshtml
To: ~/Views/ConsultantBlock/index.cshtml
Hi!
Did anyone figure this out? I have the same problem. If I, in a block view, try
@Html.PropertyFor(x => x.Title)
(which is a string),
I get this error.
The model item passed into the dictionary is of type 'System.String', but this dictionary requires a model item of type... (block type or view model)
I figured it out. It was how the view rendring was configured that caused this issue for me. I had the following configuration:
Global.asax:
ViewEngines.Engines.Add(new SiteViewEngine());
SiteViewEngine:
private static readonly string[] AdditionalPartialViewFormats = new[]
{
TemplateCoordinator.BlockFolder + "{1}.cshtml",
TemplateCoordinator.PagePartialsFolder + "{0}.cshtml"
};
This was to have the structure: Views/Blocks/LinkBlock.cshtml, instead of Views/Blocks/LinkBlock/Index.cshtml.
When I changed it to this, it worked:
private static readonly string[] NewPartialViewFormats = new[]
{
"~/Views/Blocks/{1}/{0}.cshtml"
};
Hi Josh,
I got the same error when I was trying to access GlobalSiteSetting page properties using BlockController & BlockViewModel for a newly created block, but when I tried the below method then the error was bypass.
Please try and check it's work for you:
Model:
public interface IGlobalSettings : IContentData
{
string PostalCodeValidationExpression { get; set; }
string PostalCodeValidationErrorMessage { get; set; }
}
[ContentType(GUID = "7C8C614E-E2F6-4556-A86F-F839D149B663", DisplayName = "Global Settings Page")]
public class GlobalSettingsPage : PageData, IGlobalSettings
{
[CultureSpecific]
[Display(Name = "Postal Code Validation Expression", Description = "Global validation expression for postal codes", GroupName = SystemTabNames.Content)]
public virtual string PostalCodeValidationExpression { get; set; }
[CultureSpecific]
[Display(Name = "Postal Code Validation Error Message",Description = "Global validation error message",GroupName = SystemTabNames.Content)]
public virtual string PostalCodeValidationErrorMessage { get; set; }
}
Service:
public interface IGlobalSettingsLoader
{
IGlobalSettings Get();
}
/// <summary>
/// Helper to provide access to the global settings object via member injection.
/// </summary>
public static class GlobalSettings
{
internal static Injected<IGlobalSettingsLoader> Loader { get; set; }
/// <summary>
/// Gets the global settings instance from the IoC Container via member injection. Returns an empty instance if none is found.
/// </summary>
public static IGlobalSettings Instance => Loader.Service.Get() ?? new GlobalSettingsPage();
}
View:
@{
var viewModel = new
{
postalCodeValidationExpression = GlobalSettings.Instance.PostalCodeValidationExpression,
postalCodeValidationErrorMessage = GlobalSettings.Instance.PostalCodeValidationErrorMessage,
}
}
I am running into this on alot of projects and still haven't found why or what to do to fix it.
Whenver i use a block controller for my block, and pass a view model of the block that contains lets say a content area on the block. When i go to my view and do a property for on the cotnent area that is on the block, it tries to pass the view model @model MyBlockViewModel in as the property instead of the contentarea on MyBlockViewModel. Why would the propertyfor or displayfor try to render my actual "Model" instead of the property contentarea on the model PropertyFor(x=>x.CurrentBlock.ContentArea). I am baffled.