Asp.net mvc Edit Page what can I use besides .Entry? - asp.net

I adding an admin area to an Asp.net MVC4 Application and I would consider myself a entry-level developer. My edit [HttpGet] action is working fine as it returns the values of asset. I have poured through a bunch of MVC4 specials online and most of them use the following for [HttpPost] Edit method:
[HttpPost]
public ActionResult Edit(ITTESI.AssetTracker.Web.UI.ViewModels.AssetDetailsViewModel models)
{
try
{
if (ModelState.IsValid)
{
_entities.Entry(models).State = EntityState.Modified;
_entities.SaveChanges();
return RedirectToAction("Index", new { ID = models.ID });
}
}
catch (DataException)
{
ModelState.AddModelError("", "Unable able to save changes....epic fail!!!");
}
return View(models);
}
The problem is that I do not have access to use .Entry in the following:
_entities.Entry(models).State = EntityState.Modified;
I am obviously missing a reference that will enable me to use it, but I am not sure what it is.
Here is my ViewModel(I would have used DbContext, but they did not):
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;
using ITTESI.AssetTracker.Web.UI.Content.Classes;
namespace ITTESI.AssetTracker.Web.UI.ViewModels
{
public class AssetDetailsViewModel
{
public int ID { get; set; }
public string AssetIdentifier { get; set; }
public string ManufacturerName { get; set; }
public string Model { get; set; }
public string SchoolLocation { get; set; }
public string Status { get; set; }
public string Condition { get; set; }
// [DataType(DataType.MultilineText)]
public string Notes { get; set; }
public Utils.AssignReturn AssignReturnEligible { get; set; }
public string SchoolLocationCd { get; set; }
public string SchoolLocationDisplayValue { get; set; }
public AssignedUserViewModel AssignedUserViewModelObj { get; set; }
}
}
Here is my Admin Controller:
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Metadata.Edm;
using System.Linq;
using System.Runtime.Remoting.Messaging;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using ITTESI.AssetTracker.Data.EntityModel.Entity;
using ITTESI.AssetTracker.Data.EntityModel.Definition;
using System.Data.Entity;
using ITTESI.AssetTracker.Web.UI;
using ITTESI.AssetTracker.Web.UI.Content;
using ITTESI.AssetTracker.Web.UI.Content.Classes;
using ITTESI.AssetTracker.Web.UI.ViewModelBuilders;
using ITTESI.AssetTracker.Web.UI.ViewModels;
namespace ITTESI.AssetTracker.Web.UI.Controllers
{
public class AdminController : Controller
{
ExtendedITTESI_AssetTrackerEntities _entities = new ExtendedITTESI_AssetTrackerEntities();
public ActionResult Index(ViewModels.AssetDetailsViewModel assetDetails)
{
ViewBag.PageTitle = "Admin Search";
ViewBag.HideShowLocation = "hide";
ViewBag.SubmitButtonValue = "Search";
return View("Index", assetDetails);
}
[HttpGet]
public ActionResult Edit(ITTESI_AssetTracker_Asset asset) // 'ITTESI.AssetTracker.Web.UI.ViewModels.AssetDetailsViewModel'
{
ViewBag.PageTitle = "Edit Asset";
ViewBag.SubmitButtonValue = "Save";
ViewBag.ShowLocation = true;
var model = _entities.ITTESI_AssetTracker_Asset.FirstOrDefault();
return View(model);
}
[HttpPost]
//public ActionResult Edit(ExtendedITTESI_AssetTrackerEntities ate)
public ActionResult Edit(ITTESI.AssetTracker.Web.UI.ViewModels.AssetDetailsViewModel models)
{
try
{
if (ModelState.IsValid)
{
_entities.Entry(models).State = EntityState.Modified;
_entities.SaveChanges();
return RedirectToAction("Index", new { ID = models.ID });
}
}
catch (DataException)
{
ModelState.AddModelError("", "Unable able to save changes....epic fail!!!");
}
return View(models);
}
}
}
Here is my Edit View:
#model ITTESI.AssetTracker.Data.EntityModel.Entity.ITTESI_AssetTracker_Asset
#{
ViewBag.Title = "Edit";
}
<h2>Edit</h2>
#using (Html.BeginForm()) {
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
<legend>ITTESI_AssetTracker_Asset</legend>
#Html.HiddenFor(model => model.ID)
<div class="editor-label">
#Html.LabelFor(model => model.AssetIdentifier)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.AssetIdentifier)
#Html.ValidationMessageFor(model => model.AssetIdentifier)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.AssetConditionID)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.AssetConditionID)
#Html.ValidationMessageFor(model => model.AssetConditionID)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.SchoolID)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.SchoolID)
#Html.ValidationMessageFor(model => model.SchoolID)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.AssetCategoryID)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.AssetCategoryID)
#Html.ValidationMessageFor(model => model.AssetCategoryID)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.VendorID)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.VendorID)
#Html.ValidationMessageFor(model => model.VendorID)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.AssignedPersonID)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.AssignedPersonID)
#Html.ValidationMessageFor(model => model.AssignedPersonID)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.AssetStatusID)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.AssetStatusID)
#Html.ValidationMessageFor(model => model.AssetStatusID)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.ManufacturerID)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.ManufacturerID)
#Html.ValidationMessageFor(model => model.ManufacturerID)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.ModelDetail)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.ModelDetail)
#Html.ValidationMessageFor(model => model.ModelDetail)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.CreatedOn)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.CreatedOn)
#Html.ValidationMessageFor(model => model.CreatedOn)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.CreatedByIdentifier)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.CreatedByIdentifier)
#Html.ValidationMessageFor(model => model.CreatedByIdentifier)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.ModifiedOn)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.ModifiedOn)
#Html.ValidationMessageFor(model => model.ModifiedOn)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.ModifiedByIdentifier)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.ModifiedByIdentifier)
#Html.ValidationMessageFor(model => model.ModifiedByIdentifier)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Notes)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Notes)
#Html.ValidationMessageFor(model => model.Notes)
</div>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
I also certain the problem is that DbContext for ExtendedITTESI_AssetTrackerEntities does not exist and after research a bit more that is part of the System.Data.Entity. The only code I have for ExtendedITTESI_AssetTrackerEntities is:
using System;
using Common.Logging;
using EFCachingProvider;
using EFCachingProvider.Caching;
using EFProviderWrapperToolkit;
using EFTracingProvider;
using ITTESI.AssetTracker.Data.EntityModel.Entity;
namespace ITTESI.AssetTracker.Data.EntityModel.Definition
{
public class ExtendedITTESI_AssetTrackerEntities : ITTESI_AssetTrackerEntities
{
private ILog logOutput;
public ExtendedITTESI_AssetTrackerEntities()
: this("name=ITTESI_AssetTrackerEntities")
{
}
public ExtendedITTESI_AssetTrackerEntities(string connectionString)
: base(EntityConnectionWrapperUtils.CreateEntityConnectionWithWrappers(
connectionString,
"EFTracingProvider",
"EFCachingProvider"
))
{
CachingPolicy = AssetTrackerEntitiesCachingPolicy.CachingPolicy();
Cache = AssetTrackerEntitiesCache.Cache();
}
#region Tracing Extensions
private EFTracingConnection TracingConnection
{
get { return this.UnwrapConnection<EFTracingConnection>(); }
}
public event EventHandler<CommandExecutionEventArgs> CommandExecuting
{
add { this.TracingConnection.CommandExecuting += value; }
remove { this.TracingConnection.CommandExecuting -= value; }
}
public event EventHandler<CommandExecutionEventArgs> CommandFinished
{
add { this.TracingConnection.CommandFinished += value; }
remove { this.TracingConnection.CommandFinished -= value; }
}
public event EventHandler<CommandExecutionEventArgs> CommandFailed
{
add { this.TracingConnection.CommandFailed += value; }
remove { this.TracingConnection.CommandFailed -= value; }
}
private void AppendToLog(object sender, CommandExecutionEventArgs e)
{
if (this.logOutput != null)
{
this.logOutput.Debug(e.ToTraceString().TrimEnd());
}
}
public ILog Log
{
get { return this.logOutput; }
set
{
if ((this.logOutput != null) != (value != null))
{
if (value == null)
{
CommandExecuting -= AppendToLog;
}
else
{
CommandExecuting += AppendToLog;
}
}
this.logOutput = value;
}
}
#endregion
#region Caching Extensions
private EFCachingConnection CachingConnection
{
get { return this.UnwrapConnection<EFCachingConnection>(); }
}
public ICache Cache
{
get { return CachingConnection.Cache; }
set { CachingConnection.Cache = value; }
}
public CachingPolicy CachingPolicy
{
get { return CachingConnection.CachingPolicy; }
set { CachingConnection.CachingPolicy = value; }
}
#endregion
}
}
I might have to create a model with DbContext is that fair to say?
Can I use anything besides .Entry? I appreciate the help, but with the way the app is set up I am not sure how to properly save edits back to the database.

there is a way besides .Entry for the Edit Action. EF is very clever, you can just fetch the object by ID form the database and change all the properties manually.
Ex:
[HttpPost]
public ActionResult Edit(ITTESI.AssetTracker.Web.UI.ViewModels.AssetDetailsViewModel models)
{
try
{
if (ModelState.IsValid)
{
ITTESI.AssetTracker.Web.UI.ViewModels.AssetDetailsViewModel temp = _entities.dbname.firstOrDefault(x = > x.ID == models.ID);
temp.AssetIdentifier = models.AssetIdentifier ;
temp.ManufacturerName = models.ManufacturerName ;
.
.
.
_entities.SaveChanges();
return RedirectToAction("Index", new { ID = models.ID });
}
}
catch (DataException)
{
ModelState.AddModelError("", "Unable able to save changes....epic fail!!!");
}
return View(models);
}
EF will understand what entity you want to modify, and will update it with "_entities.saveChanges();"
I don't really know that this will work for you, but I think it's worth trying

Related

asp.net mvc model didn't receive on form submit

I have written an asp.net mvc site that works fine on local.
But after publishing it, i have some problems with models sent from forms.
i think it determines my model state always not valid.
i don't receive any data!
[HttpGet]
public ActionResult LogIn()
{
return View();
}
[HttpPost]
public ActionResult LogIn(Models.LoginViewModel data)
{
if (!ModelState.IsValid)
{
return LogIn();
}
TAPortalEntities db = new TAPortalEntities();
UserAccount probableUser = db.UserAccounts.FirstOrDefault(p => p.UserName == data.UserName && p.Pass == data.Pass);
if (probableUser == null)
{
ModelState.AddModelError(string.Empty, "نام کابری یا رمز عبور اشتباه وارد شده است!");
return LogIn();
}
Session["LogedIn"] = true;
Session["UserName"] = probableUser.UserName;
Session["Course"] = probableUser.Course.Name;
Session["TeacherName"] = probableUser.Course.TeacherName;
Session["RealName"] = probableUser.RealName;
return RedirectToAction("Index", "Home");
}
and the view is like this:
#model TAPortal.Models.LoginViewModel
#{
ViewBag.Title = "ورود به سایت";
}
<h2>ورود</h2>
#using (Html.BeginForm())
{
#*#Html.AntiForgeryToken()*#
<div class="form-horizontal">
<h4>اطلاعات ورود را وارد کنید</h4>
<hr />
#Html.ValidationSummary(true)
<div class="form-group">
#Html.LabelFor(model => model.UserName, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.UserName)
#Html.ValidationMessageFor(model => model.UserName)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Pass, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Pass)
#Html.ValidationMessageFor(model => model.Pass)
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="ورود" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
#Html.ActionLink("برگشت به خانه", "Index","Home")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
and the model class :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel.DataAnnotations;
namespace TAPortal.Models
{
public class LoginViewModel
{
[Required(ErrorMessage="نام کاربری باید وارد شود!")]
[Display(Name="نام کاربری")]
public string UserName { get; set; }
[Required(ErrorMessage = "رمز عبور باید وارد شود!")]
[Display(Name = "رمز عبور")]
public string Pass { get; set; }
}
}
see these results:
input:
output local :
output on online host :
Try to add this filter
[ValidateAntiForgeryToken]
to your POST Action
Edit:
in your get method instantiate your model and set to false the ValidationSummary
[HttpGet]
public ActionResult LogIn()
{
var model = new LoginViewModel();
return View(model);
}
Now I have the answer. I share it for the others who face this problem.
From first, every thing was correct but the wrong thing was the version of the .NET framework of my host. This type of coding requires .NET framework 4.5 but my host's .NET framework version was 4.0 and it was all the story.
Now I have transferred my code to a host of 4.5.

Replacing Model object by ViewModel object will raise an exception when trying to save a new record

I have a model class named Server and I have created a new ServerToEdit viewModel class, but when I am trying to submit the viewModel I will get the following error on the repository.save() method.
The model item passed into the dictionary is of type
'TMS.Models.Server', but this dictionary requires a model item of type
'TMS.ViewModels.ServerToEdit'.
The viewModel class is :-
public class ServerToEdit
{
public Server Server { get; set; }
[Required]
public String IPAddress { get; set; }
}
Part of the Create view is:-
model TMS.ViewModels.ServerToEdit
#* This partial view defines form fields that will appear when creating and editing entities *#
#Html.AntiForgeryToken()
<div class="editor-label">
#Html.LabelFor(model => model.Server.CustomerName)
</div>
<div class="editor-field">
#Html.EditorFor(model =>model.Server.CustomerName)
#Html.ValidationMessageFor(model =>model.Server.CustomerName)
</div>
<div class="editor-label">
IP Address
</div>
<div class="editor-field">
#Html.EditorFor(model => model.IPAddress)
#Html.ValidationMessageFor(model => model.IPAddress)
</div>
IPAddress
<div class="editor-label">
#Html.LabelFor(model =>model.Server.ILOIP)
</div>
<div class="editor-field">
#Html.EditorFor(model =>model.Server.ILOIP)
#Html.ValidationMessageFor(model =>model.Server.ILOIP)
</div>
The Create actin method is :-
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(Server server, TechnologyIP technologyIP)
{
try
{
if (ModelState.IsValid)
{
repository.InsertOrUpdateServer(server,technologyIP);
repository.Save();
return RedirectToAction("Index");
}
Finally the InsertOrUpdateServer repository method is:-
public void InsertOrUpdateServer(Server server, TechnologyIP technologyIP)
{
if (server.ServerID == default(int))
{
// New entity
int technologyypeID = GetTechnologyTypeID("Server");
Technology technology = new Technology
{
IsDeleted = true,
TypeID = technologyypeID,
Tag = "S" + GetTagMaximumeNumber(technologyypeID).ToString()
};
InsertOrUpdateTechnology(technology);
Save();
var auditinfo = IntiateAudit(tms.AuditActions.SingleOrDefault(a => a.Name.ToUpper() == "ADD").ActionID,
tms.TechnologyTypes.SingleOrDefault(a => a.Name.ToUpper() == "Server").AssetTypeID,
"TDMGROUP\administrator", technology.TechnologyID);
server.ServerID = technology.TechnologyID;
technologyIP.TechnologyID = technology.TechnologyID;
tms.Servers.Add(server);
InsertOrUpdateTechnologyIP(technologyIP);
technology.IsDeleted = false;
InsertOrUpdateTechnology(technology);
InsertOrUpdateAudit(auditinfo);
}
else
{
// Existing entity
var auditinfo = IntiateAudit(tms.AuditActions.SingleOrDefault(a => a.Name.ToUpper() == "EDIT").ActionID,
tms.TechnologyTypes.SingleOrDefault(a => a.Name.ToUpper() == "Server").AssetTypeID,
"TDMGROUP\administrator", server.ServerID);
tms.Entry(server).State = EntityState.Modified;
tms.Entry(technologyIP).State = EntityState.Modified;
InsertOrUpdateAudit(auditinfo);
}
}
thanks in advance for any help ?
First of all, change your ViewModel to this:
public class ServerToEdit
{
public Server Server { get; set; }
public TechnologyIP TechnologyIP { get; set; }
}
And, change your Action to this:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(ServerToEdit serverToEdit)
{
if (ModelState.IsValid)
{
try
{
repository.InsertOrUpdateServer(serverToEdit.Server, serverToEdit.TechnologyIP);
repository.Save();
return RedirectToAction("Index");
}
catch
{
// Some code...
}
}
}
Then, in your View, you'll have:
#model TMS.ViewModels.ServerToEdit
#* This partial view defines form fields that will appear when creating and editing entities *#
#Html.AntiForgeryToken()
<div class="editor-label">
#Html.LabelFor(model => model.Server.CustomerName)
</div>
<div class="editor-field">
#Html.EditorFor(model =>model.Server.CustomerName)
#Html.ValidationMessageFor(model =>model.Server.CustomerName)
</div>
#Html.HiddenFor(model => model.TechnologyIP.TechnologyID)
<div class="editor-label">
IP Address
</div>
<div class="editor-field">
#Html.EditorFor(model => model.TechnologyIP.IPAddress)
#Html.ValidationMessageFor(model => model.TechnologyIP.IPAddress)
</div>
<div class="editor-label">
#Html.LabelFor(model =>model.Server.ILOIP)
</div>
<div class="editor-field">
#Html.EditorFor(model =>model.Server.ILOIP)
#Html.ValidationMessageFor(model =>model.Server.ILOIP)
</div>

Existing property not found

I am trying to make a dropdown box in ASP.NET, when the View is generated it gives me an error saying Categorie_ID is not found in Model Categorie (it does exist and it's public and all). The categories and product are succesfully being loaded (I have debugged that part).
Here's what I got;
My view:
#{
ViewBag.Title = #Model.Product.Merk; #Model.Product.Type;;
Layout = "~/Views/Shared/_Layout.cshtml";
}
#model WebshopProjectBlokC.ViewModels.ProductViewModel
<h2>#Model.Product.Merk #Model.Product.Type wijzigen</h2>
#using (Html.BeginForm("ProductWijzigenForm", "ProductBeheer"))
{
#Html.ValidationSummary(true)
<fieldset>
#Html.HiddenFor(model => model.Product.ID)
#Html.HiddenFor(model => model.Product.Naam)
<div class="editor-label">Prijs</div>
<div class="editor-field">
#Html.TextBoxFor(model => model.Product.Prijs)
#Html.ValidationMessageFor(model => model.Product.Prijs)</div>
<div class="editor-label">Maat</div>
<div class="editor-field">
#Html.TextBoxFor(model => model.Product.Maat)
#Html.ValidationMessageFor(model => model.Product.Maat)</div>
<div class="editor-label">Merk</div>
<div class="editor-field">
#Html.TextBoxFor(model => model.Product.Merk)
#Html.ValidationMessageFor(model => model.Product.Merk)</div>
<div class="editor-label">Type</div>
<div class="editor-field">
#Html.TextBoxFor(model => model.Product.Type)
#Html.ValidationMessageFor(model => model.Product.Type)</div>
<div class="editor-field">
#Html.DropDownListFor(model => model.SelectedID, Model.Categorien)
</div>
<div class="editor-label">URL Foto</div>
<div class="editor-field">
#Html.TextBoxFor(model => model.Product.Afbeelding)
#Html.ValidationMessageFor(model => model.Product.Afbeelding)</div>
<input type="submit" value="Wijzig" />
</fieldset>
}
The controller:
public ActionResult ProductWijzig(int productid)
{
ProductViewModel viewModel = new ProductViewModel();
Product product = ProductdataController.GetProduct(productid);
List<Categorie> catas = ProductdataController.HaalCategorienOp();
viewModel.Categorien = new SelectList(catas, "Categorie_id", "Naam");
viewModel.Product = product;
return View(viewModel);
}
The viewmodel:
namespace WebshopProjectBlokC.ViewModels
{
public class ProductViewModel
{
public Product Product { get; set; }
public Categorie Categorie { get; set; }
public SelectList Categorien { get; set; }
public int SelectedID { get; set; }
}
}
The HaalCategorienOp method;
public List<Categorie> HaalCategorienOp()
{
List<Categorie> categorien = new List<Categorie>();
try
{
conn.Open();
string selecteer = "select * from categorie";
MySqlCommand command = new MySqlCommand(selecteer, conn);
MySqlDataReader dataReader = command.ExecuteReader();
while (dataReader.Read())
{
Categorie categorie = HaalCategorieUitReader(dataReader);
categorien.Add(categorie);
}
}
catch (Exception e)
{
Console.Write("Ophalen van categorien mislukt " + e);
throw e;
}
finally
{
conn.Close();
}
return categorien;
}
HaalCategorieUitReader method;
protected Categorie HaalCategorieUitReader(MySqlDataReader datareader)
{
if (!datareader.IsDBNull(0))
{
categorie_id = datareader.GetInt32("categorie_id");
}
if (!datareader.IsDBNull(1))
{
categorienaam = datareader.GetString("naam");
}
if (!datareader.IsDBNull(2))
{
hoofdcategorie = datareader.GetInt32("hoofdcategorie");
}
Categorie categorie = new Categorie{ Categorie_id = categorie_id, Hoofdcategorie = hoofdcategorie, Naam = categorienaam};
return categorie;
}

ASP.NET MVC Page Validation Fails (The value is invalid.)

I'm trying to create ASP.NET MVC Application with Entity Framework, which has One to Many relationship. For that I have successfully managed to load the appropriate list of items to a dropdown control (in Create view), But when I click the Create button (in Create view) page validation is faild, validation error message is The value '1' is invalid..
Error
Model
public class Post
{
public int Id { get; set; }
...
public virtual Person Author { get; set; }
}
DataBaseContext
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
modelBuilder.Entity<Post>()
.HasOptional(p => p.Author);
}
Controller
public ActionResult Create()
{
PopulateAuthorDropDownList();
return View();
}
[HttpPost]
public ActionResult Create(Post post)
{
if (ModelState.IsValid)
{
db.Posts.Add(post);
db.SaveChanges();
return RedirectToAction("Index");
}
PopulateAuthorDropDownList(post.Author);
return View(post);
}
private void PopulateAuthorDropDownList(object selectedPerson = null)
{
var personQuery = from d in db.People
orderby d.Name
select d;
ViewBag.Author = new SelectList(personQuery, "Id", "Name", selectedPerson);
}
View
<div class="editor-label">
#Html.LabelFor(model => model.Author)
</div>
<div class="editor-field">
#Html.DropDownList("Author", String.Empty)
#Html.ValidationMessageFor(model => model.Author)
</div>
When I check Author table in database there is Record with Id 1, so I guess 1 is a valid value. What am I missing here?
Thanks in advance...
You didn't show how the Author object looks like,
Suppose if it is like this,
public class Author
{
public int Id{get;set;}
public string Name{get;set;}
}
Try this,
<div class="editor-label">
#Html.LabelFor(model => model.Author)
</div>
<div class="editor-field">
#Html.DropDownListFor(model => model.Author.Id, ViewBag.Author, "Select an Author")
#Html.ValidationMessageFor(model => model.Author)
</div>
Managed to fix this by
changing Model to
public class Post
{
public int Id { get; set; }
...
public int Author { get; set; } // changed type to int
}
changing View to
<div class="editor-label">
#Html.LabelFor(model => model.Author)
</div>
<div class="editor-field">
#Html.DropDownList("AuthorId", String.Empty)
#Html.ValidationMessageFor(model => model.Author)
</div>
changing Controller to
private void PopulateAuthorDropDownList(object selectedPerson = null)
{
var personQuery = from d in db.People
orderby d.Name
select d;
ViewBag.AuthorId = new SelectList(personQuery, "Id", "UserName", selectedPerson); //Changed Author to AuthorId
}
and removing
modelBuilder.Entity<Post>()
.HasOptional(p => p.Author);
from DataBaseContext
Anyway Thanks for the answers... :)
You should have something like this:
<div class="editor-label">
#Html.LabelFor(model => model.Author.Name)
</div>
<div class="editor-field">
#Html.DropDownListFor(model => model.Author.Name, (SelectList)ViewBag.AuthorList)
#Html.ValidationMessageFor(model => model.Author.Name)
</div>
Note that you should name ViewBag.AuthorList instead of ViewBag.Author
You have to provide a list of options to DropDownList where you are just passing string.empty.
And i You should use the strongly typed version DropDownListFor:
#Html.DropDownListFor(model => model.Author.Name, Model.AuthorList)
Or maybe even better by not using the name but the Id:
#Html.DropDownListFor(model => model.Author.Id, Model.AuthorList)
And your model:
class Model {
...
public SelectList AuthorList {get;set;}
}
And in your controller:
model.AuthorList = new SelectList(fetchAuthors()
.Select(a => new SelectListItem {
Text = a.Name,
Value = a.Id
}, "Value", "Text");

Content part editing view not displayed when creating a content item in Orchard

I created a content part and then added it to a content type in Orchard. But when I try to create a content item of that type, the fields for the part's properties are not displayed. I'm looking for suggestions of where the problem might be.
UPD: the relevant code:
using JetBrains.Annotations;
using ArealAds.Models;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Drivers;
using ArealAds.Models;
using ArealAds.Services;
using ArealAds.ViewModels;
namespace ArealAds.Drivers {
[UsedImplicitly]
public class AdDriver : ContentPartDriver<AdPart> {
private readonly IAdService _adService;
public AdDriver (IAdService adService)
{
_adService = adService;
}
protected override string Prefix {
get { return "AdPart"; }
}
protected override DriverResult Display(
AdPart part, string displayType, dynamic shapeHelper) {
return ContentShape("Parts_Ad", () => shapeHelper.Parts_Ad(
Title: part.Title,
Url: part.Url,
Email: part.Email,
Phone1: part.Phone1,
Phone2: part.Phone2,
AreaName: part.AreaRecord.Name,
AreaId: part.AreaRecord.Id,
DistrictName: part.DistrictRecord.Name,
DistrictId: part.DistrictRecord.Id,
AllDistricts: part.AllDistricts));
}
//GET
protected override DriverResult Editor(
AdPart part, dynamic shapeHelper) {
return ContentShape("Parts_Ad_Edit",
() => shapeHelper.EditorTemplate(
TemplateName: "Parts/Ad",
Model: BuildEditorViewModel(part),
Prefix: Prefix));
}
//POST
protected override DriverResult Editor(
AdPart part,
IUpdateModel updater,
dynamic shapeHelper) {
var model = new EditAdViewModel();
updater.TryUpdateModel(model, Prefix, null, null);
if (part.ContentItem.Id != 0) {
_adService.Update(
part.ContentItem, model);
}
return Editor(part, shapeHelper);
}
private EditAdViewModel BuildEditorViewModel(AdPart part) {
var avm = new EditAdViewModel {
Title = part.Title,
Url = part.Url,
Email = part.Email,
Phone1 = part.Phone1,
Phone2 = part.Phone2,
AllDistricts = part.AllDistricts,
Areas = _adService.GetAreas(),
Districts = _adService.GetDistricts()
};
if (part.AreaRecord != null) {
avm.AreaName = part.AreaRecord.Name;
avm.AreaId = part.AreaRecord.Id;
}
if (part.DistrictRecord != null) {
avm.DistrictName = part.DistrictRecord.Name;
avm.DistrictId = part.DistrictRecord.Id;
}
return avm;
}
}
}
using System.ComponentModel.DataAnnotations;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Records;
namespace ArealAds.Models {
public class AdRecord : ContentPartRecord {
public virtual string Title { get; set; }
public virtual string Url { get; set; }
public virtual string Email { get; set; }
public virtual string Phone1 { get; set; }
public virtual string Phone2 { get; set; }
public virtual AreaRecord AreaRecord { get; set; }
public virtual DistrictRecord DistrictRecord { get; set; }
public virtual bool AllDistricts { get; set; }
}
public class AdPart : ContentPart<AdRecord> {
[Required]
public string Title {
get { return Record.Title; }
set { Record.Title = value; }
}
public string Url {
get { return Record.Url; }
set { Record.Url = value; }
}
public string Email {
get { return Record.Email; }
set { Record.Email = value; }
}
public string Phone1 {
get { return Record.Phone1; }
set { Record.Phone1 = value; }
}
public string Phone2 {
get { return Record.Phone2; }
set { Record.Phone2 = value; }
}
public AreaRecord AreaRecord {
get { return Record.AreaRecord; }
set { Record.AreaRecord = value; }
}
public DistrictRecord DistrictRecord {
get { return Record.DistrictRecord; }
set { Record.DistrictRecord = value; }
}
[Required]
public bool AllDistricts {
get { return Record.AllDistricts; }
set { Record.AllDistricts = value; }
}
}
}
#model ArealAds.ViewModels.EditAdViewModel
<fieldset>
<legend>Area Fields</legend>
<div class="editor-label">
#Html.LabelFor(model => model.Title)
</div>
<div class="editor-field">
#Html.TextBoxFor(model => model.Title)
#Html.ValidationMessageFor(model => model.Title)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Url)
</div>
<div class="editor-field">
#Html.TextBoxFor(model => model.Url)
#Html.ValidationMessageFor(model => model.Url)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Email)
</div>
<div class="editor-field">
#Html.TextBoxFor(model => model.Email)
#Html.ValidationMessageFor(model => model.Email)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Phone1)
</div>
<div class="editor-field">
#Html.TextBoxFor(model => model.Phone1)
#Html.ValidationMessageFor(model => model.Phone1)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Phone2)
</div>
<div class="editor-field">
#Html.TextBoxFor(model => model.Phone2)
#Html.ValidationMessageFor(model => model.Phone2)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.AllDistricts)
</div>
<div class="editor-field">
#Html.CheckBoxFor(model => model.AllDistricts)
#Html.ValidationMessageFor(model => model.AllDistricts)
</div>
<table>
<tr>
<td>
<div class="editor-label">
#Html.LabelFor(model => model.AreaId)
</div>
<div class="editor-field">
#Html.DropDownListFor(model => model.AreaId,
Model.Areas.Select(s => new SelectListItem {
Selected = s.Id == Model.AreaId,
Text = s.Name,
Value = s.Id.ToString()
}),
"Выберите район...")
#Html.ValidationMessageFor(model => model.AreaId)
</div>
</td>
<td>или</td>
<td>
<div class="editor-label">
#Html.LabelFor(model => model.DistrictId)
</div>
<div class="editor-field">
#Html.DropDownListFor(model => model.DistrictId,
Model.Districts.Select(s => new SelectListItem {
Selected = s.Id == Model.DistrictId,
Text = s.Name,
Value = s.Id.ToString()
}),
"Выберите округ...")
#Html.ValidationMessageFor(model => model.DistrictId)
</div>
</td>
</tr>
</table>
</fieldset>
SchemaBuilder.CreateTable("AdRecord", table => table
.ContentPartRecord()
.Column<string>("Title")
.Column<string>("Url")
.Column<string>("Email")
.Column<string>("Phone1")
.Column<string>("Phone2")
.Column<int>("AreaRecord_Id")
.Column<int>("DistrictRecord_Id")
.Column<bool>("AllDistricts")
);
ContentDefinitionManager.AlterPartDefinition(
typeof(AdPart).Name, cfg => cfg.Attachable());
ContentDefinitionManager.AlterTypeDefinition(
"ArealAds_Ad", cfg => cfg
.WithPart("CommonPart")
.WithPart("AdPart")
.Creatable()
);
You're probably missing an entry in placement.info.
Add this into the placement.info file in your module (not the placement.info for yoru theme, since the theme is not active while you're in the dashboard):
`<Place Parts_Ad_Edit="Content:1" />`

Resources