Reputation: 13581
I am creating a module so that my clients can manage their own corporate emails as content.
The idea is to avoid putting people's real email addresses on a public website, so for a website user to send an email, I get Orchard to display a form. No problem with that. My problem (see below) is related to how Orchard displays content items in the dashboard, not the public facing part of the website.
Moving on:
I have created (see migration.cs below) a content type called EmailAddress. It is basically just a content type wrapper around a content part called CorporateEmailPart.
The other relevant bit of my setup is the driver (see CorporateEmailPartDriver.cs below). I have followed Kevin Kuebler's videos on PluralSight.com to write the driver. Debugging shows it working fine.
The shapes are placed using the Placement.info file in my module.
So, everything would be working fine if it wasn't for...
The driver correctly allows me to create the shape for the editor of my content type, which displays fine.
Or rather, displays fine to allow me to create a NEW EmailAddress. I can save the CorporateEmailPart to the database just fine.
However, when I save the new EmailAddress content type, or try to edit an existing one, the fields for the CorporateEmailPart don't display at all on my EmailAddress editor.
Ie, when in my POST DriverResult Editor method I return the GET Editor ContentShape, only the CommonPart of my Content Type is displayed (ie, the owner field of the ContentItem). No CorporateEmailPart data is displayed. Not even empty text boxes.
I must be missing something simple, cos everything else works.
But I just can't see what...!
using Orchard.ContentManagement.MetaData;
using Orchard.Core.Contents.Extensions;
using Orchard.Data;
using Orchard.Data.Migration;
using Wingspan.CorporateEmails.Models;
namespace Wingspan.CorporateEmails {
public class Migrations : DataMigrationImpl {
public int Create() {
ContentDefinitionManager.AlterTypeDefinition("EmailAddress", builder =>
builder
.WithPart("CommonPart")
.Creatable());
SchemaBuilder.CreateTable("CorporateEmailPartRecord", table =>
table.ContentPartRecord()
.Column<string>("Alias")
.Column<string>("EmailAddress")
.Column<int>("DisplayOrder")
.Column<string>("DisplayTitle")
.Column<bool>("IsDefault"));
ContentDefinitionManager.AlterPartDefinition(typeof(CorporateEmailPart).Name, p => p.Attachable());
ContentDefinitionManager.AlterTypeDefinition("EmailAddress", builder =>
builder
.WithPart(typeof(CorporateEmailPart).Name));
SchemaBuilder.CreateTable("EmailMessageRecord", table =>
table
.Column<int>("Id", col => col.PrimaryKey().Identity())
.Column<int>("CorporateEmailPartRecord_Id")
.Column<string>("Sender")
.Column<string>("Recipient")
.Column<string>("Subject")
.Column<string>("Body")
.Column<string>("TitleAndName")
.Column<string>("Address")
.Column<string>("Telephones"));
return 1;
}
}
}
using System.Collections.Generic;
using System.Web.Routing;
using Orchard;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Drivers;
using Orchard.Data;
using Orchard.Services;
using Wingspan.CorporateEmails.Models;
using Wingspan.CorporateEmails.ViewModels;
using System.Linq;
namespace Wingspan.CorporateEmails.Drivers {
public class CorporateEmailPartDriver : ContentPartDriver<CorporateEmailPart>{
private readonly IRepository<EmailMessageRecord> _repositoryEmailMessage;
private readonly IEnumerable<IHtmlFilter> _htmlFilters;
private readonly RequestContext _requestContext;
private const string TemplateName = "Parts/CorporateEmail";
protected override string Prefix
{
get
{
{ return "CorporateEmail"; }
}
}
public IOrchardServices Services { get; set; }
public CorporateEmailPartDriver(IRepository<EmailMessageRecord> repositoryEmailMessage)
{
_repositoryEmailMessage = repositoryEmailMessage;
}
public CorporateEmailPartDriver(IOrchardServices services, IEnumerable<IHtmlFilter> htmlFilters, RequestContext requestContext) {
_htmlFilters = htmlFilters;
Services = services;
_requestContext = requestContext;
}
protected override DriverResult Display(CorporateEmailPart part, string displayType, dynamic shapeHelper)
{
return ContentShape(TemplateName, () => shapeHelper.Parts_CorporateEmail(CorporateEmailPart: part));
}
//GET
protected override DriverResult Editor(CorporateEmailPart part, dynamic shapeHelper)
{
var model = BuildEditorViewModel(part);
return ContentShape("Parts_CorporateEmail_Edit", () =>
shapeHelper.EditorTemplate(TemplateName: TemplateName, Model: model, Prefix: Prefix));
}
//POST
protected override DriverResult Editor(CorporateEmailPart part, IUpdateModel updater, dynamic shapeHelper)
{
updater.TryUpdateModel(part, Prefix, null, null);
var model = BuildEditorViewModel(part);
return ContentShape("Parts_CorporateEmail_Edit",
() => shapeHelper.EditorTemplate(TemplateName: TemplateName, Model: model, Prefix: Prefix));
}
#region Private Utilities
private CorporateEmailEditorViewModel BuildEditorViewModel(CorporateEmailPart part)
{
return new CorporateEmailEditorViewModel
{
Alias = part.Alias,
EmailAddress = part.EmailAddress,
DisplayOrder = part.DisplayOrder,
DisplayTitle = part.DisplayTitle,
IsDefault = part.IsDefault,
EmailMessageSummaries = part.EmailMessages.Select(ue => ue.Summary).ToList()
};
}
#endregion
}
}
Any suggestions much appreciated.
Upvotes: 0
Views: 1897
Reputation: 13581
OK, a more careful debugging session with a clear mind and I found the issue:
An error is caused when building the viewmodel in my driver:
private CorporateEmailEditorViewModel BuildEditorViewModel(CorporateEmailPart part)
{
return new CorporateEmailEditorViewModel
{
Alias = part.Alias,
EmailAddress = part.EmailAddress,
DisplayOrder = part.DisplayOrder,
DisplayTitle = part.DisplayTitle,
IsDefault = part.IsDefault,
EmailMessageSummaries = part.EmailMessages.Select(ue => ue.Summary).ToList()
};
}
The offending line is:
EmailMessageSummaries = part.EmailMessages.Select(ue => ue.Summary).ToList()
The reason is that there is some problem with retrieving data from the EmailMessageRecord table using the CorporateEmailPartRecord_Id foreign key. I still haven't figured out what (have never used nHibernate which is what orchard uses), but the existence of this error answers the current question.
Orchard works fine.
In fact, it works really well.
What doesn'twork is the code in your module.
So be more careful with your debugging.
Kevin Kuebler's videos are a great orchard learning resource.
When you refactor the name of something, double check to make sure they have ALL been changed.
I have found what was causing the hHibernate error: shoddy refactoring.
I originally called the project CompanyEmails, but then refactored everything to call it CorporateEmails. The only problem being, I didn't refactor everything, did I? There was still a CompanyEmailPartRecord_Id field on the EmailMessageRecord model class, whereas in the database, I had changed it to CorporateEmailRecordPart_Id. So, just another bug, just a failure to refactor properly.
Upvotes: 3