I created a custom module using this guide from Orchard documentation, but for some reason I can't see the fields in the content type when I want to create a new one.
this is my model:
public class CustomerPartRecord : ContentPartRecord
{
public virtual string FirstName { get; set; }
public virtual string LastName { get; set; }
public virtual int PhoneNumber { get; set; }
public virtual string Address { get; set; }
public virtual string Profession { get; set; }
public virtual string ProDescription { get; set; }
public virtual int Hours { get; set; }
}
public class CustomerPart : ContentPart<CustomerPartRecord>
{
[Required(ErrorMessage="you must enter your first name")]
[StringLength(200)]
public string FirstName { get { return Record.FirstName; } set { Record.FirstName = value; } }
[Required(ErrorMessage = "you must enter your last name")]
[StringLength(200)]
public string LastName { get { return Record.LastName; } set { Record.LastName = value; } }
[Required(ErrorMessage = "you must enter your phone number")]
[DataType(DataType.PhoneNumber)]
public int PhoneNumber { get { return Record.PhoneNumber; } set { Record.PhoneNumber = value; } }
[StringLength(200)]
public string Address { get { return Record.Address; } set { Record.Address = value; } }
[Required(ErrorMessage = "you must enter your profession")]
[StringLength(200)]
public string Profession { get { return Record.Profession; } set { Record.Profession = value; } }
[StringLength(500)]
public string ProDescription { get { return Record.ProDescription; } set { Record.ProDescription = value; } }
[Required(ErrorMessage = "you must enter your hours")]
public int Hours { get { return Record.Hours; } set { Record.Hours = value; } }
}
this is the Handler:
class CustomerHandler : ContentHandler
{
public CustomerHandler(IRepository<CustomerPartRecord> repository)
{
Filters.Add(StorageFilter.For(repository));
}
}
the Driver:
class CustomerDriver : ContentPartDriver<CustomerPart>
{
protected override DriverResult Display(CustomerPart part, string displayType, dynamic shapeHelper)
{
return ContentShape("Parts_Customer", () => shapeHelper.Parts_Customer(
FirstName: part.FirstName,
LastName: part.LastName,
PhoneNumber: part.PhoneNumber,
Address: part.Address,
Profession: part.Profession,
ProDescription: part.ProDescription,
Hours: part.Hours));
}
//GET
protected override DriverResult Editor(CustomerPart part, dynamic shapeHelper)
{
return ContentShape("Parts_Customer", () => shapeHelper.EditorTemplate(
TemplateName:"Parts/Customer",
Model: part,
Prefix: Prefix));
}
//POST
protected override DriverResult Editor(CustomerPart part, IUpdateModel updater, dynamic shapeHelper)
{
updater.TryUpdateModel(part, Prefix, null, null);
return Editor(part, shapeHelper);
}
the migration:
public class Migrations : DataMigrationImpl
{
public int Create()
{
// Creating table CustomerPartRecord
SchemaBuilder.CreateTable("CustomerPartRecord", table => table
.ContentPartRecord()
.Column("FirstName", DbType.String)
.Column("LastName", DbType.String)
.Column("PhoneNumber", DbType.Int32)
.Column("Address", DbType.String)
.Column("Profession", DbType.String)
.Column("ProDescription", DbType.String)
.Column("Hours", DbType.Int32)
);
return 1;
}
public int UpdateFrom1()
{
ContentDefinitionManager.AlterPartDefinition("CustomerPart",
builder => builder.Attachable());
return 2;
}
public int UpdateFrom2()
{
ContentDefinitionManager.AlterTypeDefinition("Customer", cfg => cfg
.WithPart("CommonPart")
.WithPart("RoutePart")
.WithPart("BodyPart")
.WithPart("CustomerPart")
.WithPart("CommentsPart")
.WithPart("TagsPart")
.WithPart("LocalizationPart")
.Creatable()
.Indexed());
return 3;
}
}
Can someone please tell me if I am missing something?
Did you add an entry in the placement.info file? I forget that sometimes. Without placement, it won't know where to put your content so it just doesn't get rendered.
Related
Is there a way I can read Ad leads data from Lead_ID in asp.net? I see there are examples of PHP but there is no SDK for C#.Unforunately I have to use Asp.net and cannot use any other technologies
Any suggestions are highly appreciated
You can use facebook sdk c# and
var fb = new FacebookClient
{
AccessToken ="token"
};
var json = fb.Get("page_id or ad_id/leadgen_forms");
var forms = JsonConvert.DeserializeObject<FormsLeads>(json.ToString());
foreach (var form in forms.data)
{
var jsonre = fb.Get(form.id + "/leads");
var leads = JsonConvert.DeserializeObject<Leads>(jsonre.ToString());
while (leads.paging != null)
{
foreach (var lead in leads.data)
{
var leadnovo = new Models.Lead();
leadnovo.CamposExtras.Add(new CampoExtra { Nome = "idfacebook", Valor = lead.id });
leadnovo.DataCadastro = lead.created_time;
foreach (var t in lead.field_data)
{
if (t.name == "full_name")
{
leadnovo.Nome = t.values.FirstOrDefault();
}
else
if (t.name == "email")
{
leadnovo.Email = t.values.FirstOrDefault();
}
else
if (t.name == "phone_number")
{
leadnovo.Celular = t.values.FirstOrDefault();
}
else
{
leadnovo.CamposExtras.Add(new CampoExtra()
{
Nome = t.name,
Valor = t.values.FirstOrDefault()
});
}
}
if (db.Leads.FirstOrDefault(c => c.Email == leadnovo.Email) == null)
{
db.Leads.Add(leadnovo);
db.SaveChanges();
}
}
if (leads.paging != null)
{
jsonre = fb.Get(form.id + "/leads?after=" + leads.paging.cursors.after);
leads = JsonConvert.DeserializeObject<Leads>(jsonre.ToString());
}
}
}
}
Class for deserialize
public class Cursors
{
public string before { get; set; }
public string after { get; set; }
}
public class Field_Data
{
public string name { get; set; }
public string[] values { get; set; }
}
public class FormsLeads
{
public Formulario[] data { get; set; }
public Paging paging { get; set; }
}
public class Formulario
{
public string id { get; set; }
public string leadgen_export_csv_url { get; set; }
public string locale { get; set; }
public string name { get; set; }
public string status { get; set; }
}
public class Lead
{
public DateTime created_time { get; set; }
public string id { get; set; }
public Field_Data[] field_data { get; set; }
}
public class Leads
{
public Lead[] data { get; set; }
public Paging paging { get; set; }
}
public class Paging
{
public Cursors cursors { get; set; }
}
After changing relationship of Question and PossibleAnswer from Many-to-many to One-to-many I got an exception: "The changes to the database were committed successfully, but an error occurred while updating the object context. The ObjectContext might be in an inconsistent state. Inner exception message: Multiplicity constraint violated. The role 'PossibleAnswer_Question_Source' of the relationship 'WebUI.Models.PossibleAnswer_Question' has multiplicity 1 or 0..1." What does it mean?
Here is my model:
public class Question
{
public int ID { get; set; }
public string Text { get; set; }
public bool IsAssociatedWithProfessor { get; set; }
public bool IsAssociatedWithAssistant { get; set; }
public virtual ICollection<PossibleAnswer> PossibleAnswers { get; set; }
public virtual ICollection<Results> Results { get; set; }
}
public class PossibleAnswer
{
public int ID { get; set; }
public string Text { get; set; }
public virtual Question Question { get; set; }
}
And view model for Question (I know that ToQuestion should be in controller, I will rearrange it later):
public class QuestionVM
{
public QuestionVM() {
}
public QuestionVM(Question question) : this()
{
ID = question.ID;
Text = question.Text;
IsAssociatedWithProfessor = question.IsAssociatedWithProfessor;
IsAssociatedWithAssistant = question.IsAssociatedWithAssistant;
}
public int? ID { get; set; }
public string Text { get; set; }
public bool IsAssociatedWithProfessor { get; set; }
public bool IsAssociatedWithAssistant { get; set; }
private IEnumerable<string> _possibleAnswers;
public IEnumerable<string> PossibleAnswers
{
get
{
return _possibleAnswers ?? new List<string>(){"", "", "", "", ""};
}
set
{
_possibleAnswers = value;
}
}
public Question ToQuestion()
{
Question question = new Question
{
Text = this.Text,
IsAssociatedWithProfessor = this.IsAssociatedWithProfessor,
IsAssociatedWithAssistant = this.IsAssociatedWithAssistant,
PossibleAnswers = new List<PossibleAnswer>()
};
//ID will be null if creating new question
if(ID != null)
{
question.ID = (int) ID;
}
foreach (string possibleAnswer in this.PossibleAnswers)
{
if (!String.IsNullOrEmpty(possibleAnswer))
{
question.PossibleAnswers.Add(new PossibleAnswer { Text = possibleAnswer });
}
}
return question;
}
}
Here is my post method for creating new question:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult AddQuestion(QuestionVM questionVM)
{
try
{
if (ModelState.IsValid)
{
Question question = questionVM.ToQuestion();
context.Questions.Add(question);
context.SaveChanges();
return RedirectToAction("Questions");
}
}
catch (DataException /* dex */)
{
//Log the error (uncomment dex variable name and add a line here to write a log.
ModelState.AddModelError("", "Trenutno nije moguće snimiti promjene, pokušajte ponovo.");
}
return View(questionVM);
}
Line:question.PossibleAnswers.Add(new PossibleAnswer { Text = possibleAnswer });
causes the exception since I didn't save possible answers in database before I am adding them to question... But how can I add them to database without use of DbContext (since it is not a good practice to use DbContext in method which converts view model to model)?
Error is coming because PossibleAnswers are not being marked as added entity.
So update your QuestionVM like below:
public class QuestionVM
{
public QuestionVM() {
}
public QuestionVM(Question question) : this()
{
ID = question.ID;
Text = question.Text;
IsAssociatedWithProfessor = question.IsAssociatedWithProfessor;
IsAssociatedWithAssistant = question.IsAssociatedWithAssistant;
}
public int? ID { get; set; }
public string Text { get; set; }
public bool IsAssociatedWithProfessor { get; set; }
public bool IsAssociatedWithAssistant { get; set; }
private IEnumerable<string> _possibleAnswers;
public IEnumerable<string> PossibleAnswers
{
get
{
return _possibleAnswers ?? new List<string>(){"", "", "", "", ""};
}
set
{
_possibleAnswers = value;
}
}
public Question ToQuestion()
{
Question question = new Question
{
Text = this.Text,
IsAssociatedWithProfessor = this.IsAssociatedWithProfessor,
IsAssociatedWithAssistant = this.IsAssociatedWithAssistant,
PossibleAnswers = new List<PossibleAnswer>()
};
//ID will be null if creating new question
if(ID != null)
{
question.ID = (int) ID;
}
return question;
}
public List<PossibleAnswer> GetPosibleAnswers()
{
var listOfPossibleAnswers = new List<PossibleAnswer>();
foreach (string possibleAnswer in this.PossibleAnswers)
{
if (!String.IsNullOrEmpty(possibleAnswer))
{
listOfPossibleAnswers.Add(new PossibleAnswer { Text = possibleAnswer });
}
}
return listOfPossibleAnswers;
}
}
and then update your code like below.
if (ModelState.IsValid)
{
Question question = questionVM.ToQuestion();
context.Questions.Add(question);
context.SaveChanges();
question.PossibleAnswers.AddRange(questionVM.GetPosibleAnswers());
context.SaveChanges();
return RedirectToAction("Questions");
}
I am testing my controller code using IOC Unity. The issue is with the initialisation of the model that I am passing to constructor of my controller.
Here is my code in the test project
[TestMethod]
public void TestHomeControllerIndexMethod()
{
HomeController controller = new HomeController(new stubPeopleService());
ViewResult result = controller.Index() as ViewResult;
Assert.AreEqual(0, result);
}
Below is the code of the stubPeopleService that I have created which I pass to my controller constructor above
public class stubPeopleService : IPeople
{
public int Age
{
get;
set;
}
public string BirthPlace
{
get;
set;
}
public DateTime DateOfBirth
{
get;
set;
}
public int GetAge(DateTime reference, DateTime birthday)
{
int age = reference.Year - birthday.Year;
if (reference < birthday.AddYears(age)) age--;
return age + 1;
}
public int Height
{
get;
set;
}
public List<People> listPeople { get { return GetPeople(); } }
public string Name
{
get;
set;
}
public int Weight
{
get;
set;
}
private List<People> GetPeople()
{
List<People> list = new List<People>();
list.Add(new People
{
Name = "Ranjit Menon",
DateOfBirth = DateTime.Today,
BirthPlace = "London",
Age = 25,
Height = 175,
Weight = 85
});
return list.OrderBy(x => x.Name).ToList();
}
}
When I debug my test , I notice that the all the properties do not contain any value. The only property that contains value is listPeople property. The listpeople property does initialise the other properties but throws an object cannot be created error.Let me know if I am doing the test correctly. I need to do a test initialising the model with some values.
Code from my home controller
private IPeople peopleService;
public HomeController(IPeople people)
{
this.peopleService = people;
}
public ActionResult Index()
{
return View(peopleService);
}
Please find the IPeople interface below
public interface IPeople
{
int Age { get; set; }
string BirthPlace { get; set; }
DateTime DateOfBirth { get; set; }
int GetAge(DateTime reference, DateTime birthday);
int Height { get; set; }
List<People> listPeople { get; }
string Name { get; set; }
int Weight { get; set; }
}
I've a problem with orchard.
I've created a widget that is a video player, it's a simple widget with the class ContentPartRecord:
public class VideoPlayerPartRecord : ContentPartRecord
{
public virtual string MediaFile { get; set; }
public virtual int Width { get; set; }
public virtual int Height { get; set; }
public virtual bool AutoStart { get; set; }
public virtual bool Repeat { get; set; }
}
and the class ContentPart:
public class VideoPlayerPart : ContentPart<VideoPlayerPartRecord>
{
[Required(ErrorMessage = "Media File required")]
[Display(Name = "Media File: ")]
public string MediaFile
{
get { return Record.MediaFile; }
set { Record.MediaFile = value; }
}
[Required(ErrorMessage = "Width required")]
[Display(Name = "Width: ")]
public int Width
{
get { return Record.Width; }
set { Record.Width = value; }
}
[Required(ErrorMessage = "Height required")]
[Display(Name = "Height: ")]
public int Height
{
get { return Record.Height; }
set { Record.Height = value; }
}
[Display(Name = "Auto Start: ")]
public bool AutoStart
{
get { return Record.AutoStart; }
set { Record.AutoStart = value; }
}
[Display(Name = "Repeat: ")]
public bool Repeat
{
get { return Record.Repeat; }
set { Record.Repeat = value; }
}
}
this is the file migration:
public class Migrations : DataMigrationImpl {
public int Create() {
// Creating table default_Raise_VideoPlayer_VideoPlayePartRecord
SchemaBuilder.CreateTable("default_Raise_VideoPlayer_VideoPlayePartRecord", table => table
.ContentPartRecord()
.Column("MediaFile", DbType.String)
.Column("Width", DbType.Int32)
.Column("Height", DbType.Int32)
.Column("AutoStart", DbType.Boolean)
.Column("Repeat", DbType.Boolean)
);
ContentDefinitionManager.AlterPartDefinition(typeof(VideoPlayerPart).Name, cfg => cfg
.Attachable());
return 1;
}
public int UpdateFrom1() {
ContentDefinitionManager.AlterTypeDefinition("VideoPlayerWidget", cfg => cfg
.WithPart("VideoPlayerPart")
.WithPart("WidgetPart")
.WithPart("CommonPart")
.WithSetting("Stereotype", "Widget"));
return 2;
}
}
the problem is that when I insert the widget it is added but I can't see it. Why??
You need to add a Handler for your widget to persist the item, and a placement.info entry to present it.
http://docs.orchardproject.net/Documentation/Writing-a-content-part
(code taken from article)
using Maps.Models;
using Orchard.ContentManagement.Handlers;
using Orchard.Data;
namespace Maps.Handlers {
public class MapHandler : ContentHandler {
public MapHandler(IRepository<MapRecord> repository) {
Filters.Add(StorageFilter.For(repository));
}
}
}
and Placement.info
<Placement>
<Place Parts_Map="Content:10"/>
<Place Parts_Map_Edit="Content:7.5"/>
</Placement>
If it doesn't save into a database - its probably the handler. If it doesn't display on screen, it's probably placement.info
Also you didn't mention having a driver or a view, but I'd guess it is the Handler or the placement info you are missing. Also, check spelling and convention very carefully when relating the driver, migration and placement info, as there are several places you can use the wrong text string if you create your parts manually.
Building my first module in Orchard, and everything but the save (on some fields) is working. I get no errors on save, the fields just show their default value with no values being inserted/updated in the database table.
I built the module with only one property at first, and then added more to the recordpart once I confirmed things updated from the admin. Now the new fields show up in the editor, but only the original property (SoldOut) is saving on update or create. I saw another post that recommended deleting the mappings.bin file, but that didn't change anything. Thanks for any help!
Here's the main classes:
public class ConferencePartRecord : ContentPartRecord
{
public virtual bool OnlyShowTeaser { get; set; }
public virtual int TheYear { get; set; }
public virtual DateTime StartDate { get; set; }
public virtual DateTime EndDate { get; set; }
public virtual DateTime EarlyReg { get; set; }
public virtual DateTime RegularReg { get; set; }
public virtual DateTime LateReg { get; set; }
public virtual DateTime ConfirmDate { get; set; }
public virtual bool SoldOut { get; set; }
public virtual bool ConferenceSpace { get; set; }
public virtual int EarlyBirdException { get; set; }
public virtual string NextConf { get; set; }
}
public class ConferencePart : ContentPart<ConferencePartRecord>
{
public bool OnlyShowTeaser
{
get { return Record.OnlyShowTeaser; }
set { Record.OnlyShowTeaser = value; }
}
public int TheYear
{
get { return Record.TheYear; }
set { Record.TheYear = value; }
}
public DateTime StartDate
{
get { return Record.StartDate; }
set { Record.StartDate = value; }
}
public DateTime EndDate
{
get { return Record.EndDate; }
set { Record.EndDate = value; }
}
public DateTime EarlyReg
{
get { return Record.EarlyReg; }
set { Record.EarlyReg = value; }
}
public DateTime RegularReg
{
get { return Record.RegularReg; }
set { Record.RegularReg = value; }
}
public DateTime LateReg
{
get { return Record.LateReg; }
set { Record.LateReg = value; }
}
public DateTime ConfirmDate
{
get { return Record.ConfirmDate; }
set { Record.ConfirmDate = value; }
}
public bool ConferenceSpace
{
get { return Record.ConferenceSpace; }
set { Record.ConferenceSpace = value; }
}
public int EarlyBirdException
{
get { return Record.EarlyBirdException; }
set { Record.EarlyBirdException = value; }
}
public String NextConf
{
get { return Record.NextConf; }
set { Record.NextConf = value; }
}
public bool SoldOut
{
get { return Record.SoldOut; }
set { Record.SoldOut = value; }
}
}
Here is my driver class:
public class ConferenceDriver : ContentPartDriver<AeriesConference.Models.ConferencePart>
{
protected override DriverResult Display(ConferencePart part, string displayType, dynamic shapeHelper)
{
return ContentShape("Parts_Conference", () => shapeHelper.Parts_Conference(SoldOut: part.SoldOut));
}
//GET
protected override DriverResult Editor(ConferencePart part, dynamic shapeHelper)
{
return ContentShape("Parts_Conference_Edit",
() => shapeHelper.EditorTemplate(
TemplateName: "Parts/Conference",
Model: part,
Prefix: Prefix));
}
//POST
protected override DriverResult Editor(ConferencePart part, IUpdateModel updater, dynamic shapeHelper)
{
updater.TryUpdateModel(part, Prefix, null, null);
return Editor(part, shapeHelper);
}
}
... the migrations.cs class (so you can see my updates - which are all reflected in the DB)
public int Create() {
// Creating table ConferenceRecord
SchemaBuilder.CreateTable("ConferencePartRecord", table => table
.ContentPartRecord()
.Column("SoldOut", DbType.Boolean)
);
return 1;
}
public int UpdateFrom1()
{
// Create (or alter) a part called "ConferencePart" and configure it to be "attachable".
ContentDefinitionManager.AlterPartDefinition("ConferencePart", part => part
.Attachable());
return 2;
}
public int UpdateFrom2()
{
SchemaBuilder.AlterTable("ConferencePartRecord", table => table.AddColumn("OnlyShowTeaser", DbType.Boolean));
SchemaBuilder.AlterTable("ConferencePartRecord", table => table.AddColumn("TheYear", DbType.Int16));
SchemaBuilder.AlterTable("ConferencePartRecord", table => table.AddColumn("StartDate", DbType.DateTime));
SchemaBuilder.AlterTable("ConferencePartRecord", table => table.AddColumn("EndDate", DbType.DateTime));
SchemaBuilder.AlterTable("ConferencePartRecord", table => table.AddColumn("EarlyReg", DbType.DateTime));
SchemaBuilder.AlterTable("ConferencePartRecord", table => table.AddColumn("RegularReg", DbType.DateTime));
SchemaBuilder.AlterTable("ConferencePartRecord", table => table.AddColumn("LateReg", DbType.DateTime));
SchemaBuilder.AlterTable("ConferencePartRecord", table => table.AddColumn("ConfirmDate", DbType.DateTime));
SchemaBuilder.AlterTable("ConferencePartRecord", table => table.AddColumn("ConferenceSpace", DbType.Boolean));
SchemaBuilder.AlterTable("ConferencePartRecord", table => table.AddColumn("EarlyBirdException", DbType.Int16));
SchemaBuilder.AlterTable("ConferencePartRecord", table => table.AddColumn("NextConf", DbType.String));
return 3;
}
}
and, finally, my handler class:
public class ConferencePartHandler : ContentHandler
{
public ConferencePartHandler(IRepository<ConferencePartRecord> repository)
{
Filters.Add(StorageFilter.For(repository));
}
}
Of course, I found the issue 5 minutes after posting the question. I had missed one of the datetime fields in the cshtml file for the editor, and when it was saving to the database it was dying on the update since the date column won't take a null.