Help with implementing a Frontend Control Panel for Users [1.10]

Hey Guys, I have inherited some code and I'm trying to setup a rudimentary control panel [frontend] for users that basically replicates what I have currently in the backend.

Currently the Display driver is returning just a few elements of 'Profile' [A part extending 'User'], whereas my drivers Editor [admin] displays the entire profile and associated addresses and locations for editing; 'I wish them to be basically the same.'

namespace CE.Drivers
public class ProfilePartDriver : ContentPartDriver<ProfilePart>
    private readonly IProfileService _profileService;
    private readonly IAddressService _addressService;
    private readonly ILocationService _locationService;

    private const string TemplateName = "Parts/Profile";

    public ProfilePartDriver(IProfileService profileService, IAddressService addressService, ILocationService locationService)
        _profileService = profileService;
        _addressService = addressService;
        _locationService = locationService;

    protected override string Prefix
        get { return "Profile"; }

    protected override DriverResult Display(ProfilePart part, string displayType, dynamic shapeHelper)
        return ContentShape("Parts_Profile",
                        () => shapeHelper.Parts_Profile(
                            ContentPart: part,
                            Id: part.Id,
                            Newsletter: part.Newsletter,
                            FirstName: part.FirstName,
                            LastName: part.LastName

    protected override DriverResult Editor(ProfilePart part, dynamic shapeHelper)
        return ContentShape("Parts_Profile_Edit",
                () => shapeHelper.EditorTemplate(
                    TemplateName: TemplateName,
                    Model: BuildEditorViewModel(part),
                    Prefix: Prefix));

    protected override DriverResult Editor(ProfilePart part, IUpdateModel updater, dynamic shapeHelper)
        var model = new EditProfileViewModel();
        updater.TryUpdateModel(model, Prefix, null, null);

        if (part.ContentItem.Id != 0)
                part.ContentItem, model);

        return Editor(part, shapeHelper);

    private EditProfileViewModel BuildEditorViewModel(ProfilePart part)
        var addressvm = _addressService.GetAddressesOfProfile(part.Id).Select(x => new AddressViewModel
            Id = x.Id,
            Street1 = x.Street1,
            Street2 = x.Street2,
            City = x.City,
            PostCode = x.PostCode,
            State = x.State,
            Country = x.Country

        var locationvm = _locationService.GetLocationsOfProfile(part.Id).Select(x => new LocationViewModel
            Id = x.Id,
            Type = x.Type,
            Name = x.Name,
            Size = x.Size,

        var dvm = new EditProfileViewModel()
            Id = part.Id,
            Newsletter = part.Newsletter,
            FirstName = part.FirstName,
            LastName = part.LastName,

            Address = addressvm,

            Location = locationvm

        return dvm;

When I try to replicate the editors code within display, I get Error's stating that it expects ZoneHOlding Object, and not EditProfileViewModel?

My Profile.cshtml

    public ActionResult Index(string username)
        // Route constraint [ProfileRoutes.cs (Match)] checks if 'actual' user exists, this checks if
        // user is logged in or not, and if the currentUser can view Profile[s]
        IUser user = _workContextAccessor.GetContext().CurrentUser;

        if (user == null) return HttpNotFound(); // Todo: return signup page

        // Current User tries to input another Valid username [not his/hers], 
        // but allow user that enters url without their name (which is valid) after EA/Profile i.e. it will be null
        if (!user.UserName.Equals(username, StringComparison.OrdinalIgnoreCase) && username != null) return HttpNotFound();

        //  Is the user Authorized to view this profile[s]
        if (!_orchardServices.Authorizer.Authorize(Permissions.ViewProfiles, user, null)) return HttpNotFound();

        dynamic shape = _orchardServices.ContentManager.BuildDisplay(_profileService.GetProfile(user.Id).ContentItem);
        //var vm = BuildEditorViewModel(_orchardServices.ContentManager.Get<ProfilePart>(user.Id));//, VersionOptions.Published, QueryHints.Empty);
        return View((object)shape);

What is the correct way to go about this, should I just forget about shapes and return a viewModel? Thanks for your time and any suggestions - much appreciated, Pug

Re: Help with implementing a Frontend Control Panel for Users [1.10]

Although you didn't show your view, I bet its Model type is not the same as dynamic, but EditProfileViewModel. If your view declares one type as its model, you need to actually provide an instance of that type from your controller to that view.

If I understood correctly, you want to reuse the code from the ProfilePartDriver, without invoking the other parts attached to the user. Because you will need to use IContentManager.BuildEditor to invoke the Editor methods on those drivers, this won't work without some hacking, since you cannot provide your own display type (like you can with BuildDisplay). If you could, then it would be a simple matter of calling BuildEditor on the User content item, passing in a custom display type, and having your custom Placement.info file setup to only display the PartsProfileEdit shape.

So the most straightforward way in this case is to build your view model, send it to the view, and have a POST controller action handle the post back, copying over fields from the view model onto the profile part, one by one. Which is pretty much what you already have in your controller. Instead of returning a shape, return the view model (which you commented out).

Wednesday, January 18, 2017 10:26:22 AM bysfmskywalker

Post a reply

You need to be signed in to post a reply.

Sign In