Broken DnD with backingtype PropertyPageReference but property type is custom content

Vote:
 

I have this:

        [BackingType(typeof(PropertyContentReference))]
        [AllowedTypes(typeof(Contact)), Required]
        public virtual Contact Contact
        {
            get
            {
                var contentRef = this.GetPropertyValue(this.GetPropertyName(x => x.Contact));
                if (ContentReference.IsNullOrEmpty(contentRef))
                    return null;
                return ServiceLocator.Current.GetInstance().Get(contentRef);
            }
            set
            {
                this.SetValue(this.GetPropertyName(x => x.Contact), value);
            }
        }

The property works as I like, but DnD is borken. I get an error in the UI:

Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'EPiServer.Core.ContentReference' because the type requires a JSON string value to deserialize correctly. To fix this error either change the JSON to a JSON string value or change the deserialized type so that it is a normal .NET type (e.g. not a primitive type like integer, not a collection type like an array or List) that can be deserialized from a JSON object. JsonObjectAttribute can also be added to the type to force it to deserialize from a JSON object. Path 'isPreferredLanguageAvailable', line 1, position 32.
I guess it has something to do with the property returning a Contact and not a ContentReference? If i change the property to a ContentReference it works.
What am I missing?
#155412
Sep 16, 2016 8:47
Vote:
 

I don't have a solution for your DnB problem at the moment, but I do have a suggestion how you can do it in another way. I would just create two properties on the content type:

public virtual ContentReference ContactContentLink { get; set; }

public Contact Contact
{
    get
    {
        if (ContentReference.IsNullOrEmpty(this.ContactContentLink))
            return null;

        return ServiceLocator.Current.GetInstance<IContentLoader>().Get<Contact>(this.ContactContentLink);
    }
}


I would also consider if it's really needed to have the Contact property on the model itself. It could easily be populated on a view model or by using an extension method the get the Contact from the ContentReference.

#155477
Sep 19, 2016 9:32
Vote:
 

Btw, you can create a display template for your ContentReference property called ContactReference.cshtml and put in i /Views/Shared/DisplayTemplates. This way you can drag and drop a contact and it will get updated instantly in the on-page edit view:

@using EPiServer.ServiceLocation
@model ContentReference

@{
    Contact contact;
    var contentLoader = ServiceLocator.Current.GetInstance<IContentLoader>();

    if (ContentReference.IsNullOrEmpty(Model) || contentLoader.TryGet(Model, out contact) == false)
    {
        return;
    }

    Html.RenderContentData(contact, false);
}

Then in your view where you want your contact. You can of course add a UIHint attribute to your property as well and skip the second parameter in the PropertyFor helper:

@Html.PropertyFor(m => m.ContactContentLink, "ContactReference")
#155503
Edited, Sep 19, 2016 16:27
Vote:
 

Tnx for reply!

Yes, i'm aware of that. I just want clean models without unecessary properties :P I guess i could create a view model with the Contact typed property and have ContentRefernce property on my contenttype or something.

I this case i'm not rendering the property it self, the Contact object is just pure data that is used from contact blocks and such :)

#155504
Edited, Sep 19, 2016 16:31
* 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.