How to change the text of a drop dowlist? - asp.net-mvc

I have a dropdowlist in my view
<div class="editor-label">
#Html.LabelFor(model => model.SubProcessId, "SubProcess")
</div>
<div class="editor-field">
#Html.DropDownList("SubProcessId", ViewBag.SubProcessId as SelectList)
#Html.ValidationMessageFor(model => model.SubProcessId)
</div>
That has this model
namespace CTTModel
{
using System;
using System.Collections.Generic;
public partial class **SubProcess**
{
public SubProcess()
{
this.Risks = new HashSet<Risk>();
}
public int Id { get; set; }
public string Name { get; set; }
public int ProcessId { get; set; }
public string Description { get; set; }
public virtual **Process** Process { get; set; }
public virtual ICollection<Risk> Risks { get; set; }
}
}
which appears in the view via this controller
public ActionResult Create()
{
try
{
// Risk
**ViewBag.SubProcessId = new SelectList(_db.SubProcesses, "Id", "Name", "Process");**
ViewBag.RiskSeverityId = new SelectList(_db.RiskSeverities, "Id", "Name");
ViewBag.RiskFrequencyId = new SelectList(_db.RiskFrequencies, "Id", "Name");
ViewBag.RiskRatingId = new SelectList(_db.RiskRatings, "Id", "Name");
ViewBag.RiskType1Id = new SelectList(_db.RiskType1, "Id", "Name");
ViewBag.RiskType2Id = new SelectList(_db.RiskType2, "Id", "Name");
//Test
ViewBag.RegionLevelId = new SelectList(_db.RegionLevels, "Id", "Name");
}
catch (Exception ex)
{
throw;
}
return View();
}
These are the suprocesses that show in the dropdownlist
Past due collection
Dealer audits
Credit Watch classification
Reconciliation
Control
Every sub process can have on process
Portfolio Management
Finance
Test Modeling
Now I was asked to show in the dropdownlist not the subprocess name, but instead
"<process name> - <subprocess name>"
Portfolio Management - Reconciliation, for example
And I have the faintest idea how to do that.
Any ideas??

var subProcessList = _db.SubProcesses
.Select(x => new
{
Id = x.Id,
Name = string.Format("{0} - {1}", x.Process.Name, x.Name)
})
.ToList();
ViewBag.SubProcessId = new SelectList(subProcessList, "Id", "Name");

Related

Asp.Net MVC dropdownlist not posting value to controller -> database

my development environment is ASP.NET MVC 5 using Entity Framework 6 using a code-first workflow.
My problem: When trying to add a new record to the database, the values from my two dropdownlists are not being included. All the other fields are indeed saving to the database.
I am passing a ViewModel to the view in question:
public class NewItemViewModel
{
public IEnumerable<Category> Categories { get; set; }
public Item Item { get; set; }
public IEnumerable<Donor> Donors { get; set; }
}
The domain models I am using:
public class Item
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public int Quantity { get; set; }
public bool IsActive { get; set; }
public Category Category { get; set; }
public Donor Donor { get; set; }
}
public class Category
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Donor
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string FullName { get { return FirstName + " " + LastName; } }
public string Email { get; set; }
}
The relevant controller: This New() action is simply used to pass data to the view for the form to be submitted
public ActionResult New()
{
var itemCategories = _context.ItemCategory.ToList();
var donors = _context.Donors.ToList();
var viewModel = new NewItemViewModel
{
Categories = itemCategories,
Donors = donors
};
return View(viewModel);
}
Here is my actual action that adds the submitted data to the database:
// Create a new item.
[HttpPost]
public ActionResult Create(Item item)
{
_context.Items.Add(item);
_context.SaveChanges();
return RedirectToAction("Index", "Item");
}
And lastly, the view itself (I will minimize the code here):
#using (Html.BeginForm("Create", "Item"))
{
<div class="form-group">
#Html.LabelFor(m => m.Item.Donor)
#Html.DropDownListFor(m => m.Item.Donor, new SelectList(Model.Donors, "Id", "FullName"), "Who donated this item?", new { #class = "form-control" })
</div>
<div class="form-group">
#Html.LabelFor(m => m.Item.Category)
#Html.DropDownListFor(m => m.Item.Category, new SelectList(Model.Categories, "Id", "Name"), "Select Item Category", new { #class = "form-control" })
</div>
}
To reiterate the problem I am having: The values of the dropdownlist for Category and Donor are not saving to the database, whereas the others (non-navigation properties?) Name, Description, Quantity, etc. is working correctly.
Am I using the ViewModel the right way? I was under the impression that the MVC framework knows how to deal with passing the Item object parameter in the Create() action - mapping what it needs to within the Item entity.
Any help would be much appreciated. Thank you.
In the NewItemViewModel you have not created property to hold the selected values from dropdown
public class NewItemViewModel
{
public IEnumerable<Category> Categories { get; set; }
public int SelectedCategory{get;set;}
public Item Item { get; set; }
public int SelectedDonor{get;set;}
public IEnumerable<Donor> Donors { get; set; }
}
#using (Html.BeginForm("Create", "Item"))
{
<div class="form-group">
#Html.LabelFor(m => m.Item.Donor)
#Html.DropDownListFor(m => m.SelectedDonor, new SelectList(Model.Donors, "Id", "FullName"), "Who donated this item?", new { #class = "form-control" })
</div>
<div class="form-group">
#Html.LabelFor(m => m.Item.Category)
#Html.DropDownListFor(m => m.SelectedCategory, new SelectList(Model.Categories, "Id", "Name"), "Select Item Category", new { #class = "form-control" })
</div>
}

The ViewData item that has the key 'Position' is of type 'System.String' but must be of type 'IEnumerable<SelectListItem>' [duplicate]

This question already has answers here:
The ViewData item that has the key 'XXX' is of type 'System.Int32' but must be of type 'IEnumerable<SelectListItem>'
(6 answers)
Closed 6 years ago.
I am populating DropDownList from in-memory data and getting this error on POST.
The ViewData item that has the key 'Position' is of type 'System.String' but must be of type 'IEnumerable'.
Model:
public class StaffModel
{
public int id { get; set; }
public string Email { get; set; }
[DataType(DataType.Password)]
public string Password { get; set; }
[DataType(DataType.Password)]
public string PasswordConfirm { get; set; }
public string Emp_Name { get; set; }
public string Emp_Address { get; set; }
public string Phone { get; set; }
public string Position { get; set; }
public List<SelectListItem> Positions { set; get; }
}
Controller:
public ActionResult Register()
{
IEnumerable<SelectListItem> position = db.Positions.Select(p => new SelectListItem
{
Text = p.Position_Title,
Value = p.Position_ID.ToString()
});
ViewBag.Position = position;
return View();
}
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Register(StaffModel model)
{
if (ModelState.IsValid)
{
var user = new ApplicationUser { UserName = model.Email, Email = model.Email };
var result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
Employee em = new Employee
{
Employee_Name = model.Emp_Name,
Address = model.Emp_Address,
Phone = model.Phone,
Position_ID = Convert.ToInt32(db.Positions.Where(p => p.Position_Title == model.Position).Select(p => p.Position_ID)),
};
db.Employees.Add(em);
db.SaveChanges();
return RedirectToAction("Index", "Employees");
}
}
return View(model);
}
enter code here
HTML/Razor:
<div class="form-group">
#Html.LabelFor(model => model.Position, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("Position",null, htmlAttributes: new { #class = "form-control" } )
#Html.ValidationMessageFor(model => model.Position, "", new { #class = "text-danger" })
</div>
</div>
Your binding on the drop down list doesn't look right.
You're model contains Positions which is the data for your drop down. You also have "Position" which I presume is a string that will be bound to the selected value in the drop down.
Change your view to
#Html.DropDownListFor(x=> x.Position, Model.Positions, new {#class = "form-control"}) )
Then on your post, it looks as if you are trying to get the value selected from the drop down by performing a linq query on the "Positions" list of the model which was used to populate your dropdown. You should now have the selected value in the "Position" property of your model.
So you should say
Position_ID = model.Position
I'd also use a model for your Register View.
Something like...
public class RegisterViewModel
{
public IEnumerable<SelectListItem> Positions { get; set; }
public string Position { get; set; }
}
Plus the additional fields you need.
The in your Register action method, populate the view model and return the view.
public ActionResult Register()
{
var regModel = new RegisterViewModel
{
Positions = db.Positions.Select(p => new SelectListItem
{
Text = p.Position_Title,
Value = p.Position_ID.ToString()
})
};
return View("Register",regModel);
}
You don't need to use ViewBag now.
Hope that helps
it work correctly. thank everybody help me:D
Model:
public class StaffModel
{
public string Position { get; set; }
public List<Position> Positions { set; get; }
public int selectID { get; set; }
}
Controller:
public ActionResult Register()
{
StaffModel st = new StaffModel();
st.Positions = db.Positions.ToList();
return View(st);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Register(StaffModel model)
{
if (ModelState.IsValid)
{
var user = new ApplicationUser { UserName = model.Email, Email = model.Email };
var result = UserManager.Create(user, model.Password);
if (result.Succeeded)
{
Employee em = new Employee
{
Employee_Name = model.Emp_Name,
Address = model.Emp_Address,
Phone = model.Phone,
Position_ID = model.selectID,
ID_User = user.Id
};
db.Employees.Add(em);
db.SaveChanges();
return RedirectToAction("Index", "Employees");
}
else
AddErrors(result);
}
ViewBag.Position = new SelectList(db.Positions, "Position_ID", "Position_Title");
return View(model);
}
HTML/Razor:
<div class="form-group">
#Html.LabelFor(model => model.Position, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownListFor(model=>model.selectID,new SelectList(Model.Positions, "Position_ID", "Position_Title"), htmlAttributes: new { #class = "form-control" } )
#Html.ValidationMessageFor(model => model.Position, "", new { #class = "text-danger" })
</div>
</div>

Create View with Model and List<Model>

I have a project model and a technology model. There can be multiple technologies in one project. There will be a limited amount of technology objects, around 5-10, that will be used across an unlimited amount of projects. I thought of keeping the technology items in an enum or just as constant variables, but I want the ability to add or edit down the road, so I figured I would put them in a table.
I tend to get hung up when dealing with lists. I want to be able to create a single project, and in the same view check a checkbox for the technology that was used on the project (ex. HTML5 or CSS3). I am not able to get a list of technologies to show up in the view for me to mark as checked for the particular project.
Project Class:
public class Project
{
public int Id { get; set; }
public string Website { get; set; }
public List<Technology> Technologies { get; set; }
}
Technology Class:
public class Technology
{
public int Id { get; set; }
public string Name { get; set; }
public bool IsActive { get; set; }
}
ViewModel:
public class ProjectTechnologyViewModel
{
public IEnumerable<Technology> Technologies { get; set; }
public Project Projects { get; set; }
public ProjectTechnologyViewModel()
{
Projects = new Project();
}
}
DbContext:
public class NovaDB : DbContext
{
public NovaDB(): base("DefaultConnection")
{
}
public DbSet<Technology> Technologies { get; set; }
public DbSet<Project> Projects{ get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
}
Controller:
public ActionResult CreateProject()
{
return View();
}
[HttpPost]
public ActionResult CreateProject(ProjectTechnologyViewModel viewModel)
{
var proj = new Project();
if (ModelState.IsValid)
{
proj.LaunchDate = viewModel.Projects.LaunchDate;
proj.ProjectType = viewModel.Projects.ProjectType;
proj.ServiceId = viewModel.Projects.ServiceId;
proj.ShowInOurWork = viewModel.Projects.ShowInOurWork;
proj.Website = proj.Website;
proj.Technologies = new List<Technology>();
foreach (var t in viewModel.Technologies)
{
proj.Technologies.Add(new Technology()
{
Name = t.Name,
FAClassName = t.FAClassName,
IsActive = t.IsActive,
});
}
_db.Projects.AddOrUpdate(proj);
_db.SaveChanges();
}
return View(proj);
}
View:
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Project</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.Projects.Website, htmlAttributes: new {#class = "control-label col-md-2"})
<div class="col-md-10">
#Html.EditorFor(model => model.Projects.Website, new {htmlAttributes = new {#class = "form-control"}})
#Html.ValidationMessageFor(model => model.Projects.Website, "", new {#class = "text-danger"})
</div>
</div>
#for (int i = 0; i < Model.Technologies.Count(); i++)
{
#Html.CheckBoxFor(x=>x.Technologies[i].)
}
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
Image of View:
The checkbox is for the IsActive property of the Technology, right? So, you can do this:
#Html.CheckBoxFor(model => model.Technologies.ToList()[i].IsActive) #Model.Technologies.ToList()[i].Name
You also need to instantiate your ViewModel and send it to your view in your GET action, like this:
public ActionResult CreateProject()
{
var model = new ProjectTechnologyViewModel();
model.Project = new Project();
model.Technologies = new List<Technology>();
return View(model);
}
Also, don't instantiate the properties in your ViewModel. Do that in your controller (see above):
public class ProjectTechnologyViewModel
{
public IEnumerable<Technology> Technologies { get; set; }
public Project Project { get; set; }
}
Why are you referring to a IEnumerable as an array?
this - someIEnumerable[0] will not be compiled.
Why don't you use foreach?
foreach(var i in Model.Technologies){
var a = i.Website;
}
Firstly, you will need a table to store the Technologies associated with a Project, (say ProjectTechnlogies) that will include FK fields to the Project ID field and the Technology ID field.
Then you will need view models to represent what your wanting to edit in the view
public class TechnologyVM
{
public int Id { get; set; }
public string Name { get; set; }
public bool IsSelected { get; set; } // for binding to a checkbox
}
public class ProjectVM
{
public string Website { get; set; }
public IEnumerable<TechnologyVM> Technologies { get; set; }
}
and your GET method would be
public ActionResult Create()
{
ProjectVM model = new ProjectVM
{
Technologies = _db.Technologies.Where(t => t.IsActive).Select(t => new TechnologyVM
{
Id = t.Id,
Name = t.Name
})
};
return View(model);
}
Note I am assuming here that your IsActive property means that if the value is false its now an obsolete technology (it may have been assigned to previous Projects) and that you don't want to allow to to be selected in the view when creating a new Project.
Then create an EditorTemplate (partial) for TechnologyVM in /Views/Shared/EditorTemplates/TechnologyVM.cshtml (note the name of the file must match the name of the class)
#model TechnologyVM
<div>
#Html.HiddenFor(m => m.Id)
#Html.HiddenFor(m => m.Name) // if you want this value to be posted
#Html.CheckBoxFor(m => m.IsSelected)
#Html.LabelFor(m => m.IsSelected, Model.Name)
</div>
and the main view will be
#model ProjectVM
....
#using (Html.BeginForm())
{
....
#Html.TextBoxFor(m => m.Website)
....
#Html.EditorFor(m => m.Technologies)
<input type="submit" ... />
}
The EditorFor() method will correctly generate the html for each Technology
Finally you POST method will be
[HttpPost]
public ActionResult Create(ProjectVM model)
{
if (!ModelState.IsValid)
{
return View(model);
}
Project project = new Project
{
Website = model.Website,
// ... other properties of Project
}
_db.Projects.Add(project);
_db.SaveChanges(); // The Project's Id property has now been set
IEnumerable<int> selectedTechnologies = model.Where(t => t.IsSelected).Select(t => t.Id);
foreach(int ID in selectedTechnologies)
{
ProjectTechnology technology = new ProjectTechnology
{
ProjectId = project.Id,
Technology = ID
};
_db.ProjectTechnologies.Add(technology);
}
_db.SaveChanges(); // save the project technologies
// redirect
}
I had to change a few models and I added a table to map the two models. I decided to save the "link" between the Project & Technology models in a shared table called ProjectTechnologyMap. For the project I create, I insert a record with the project Id and the Technology Id. The project Id stays constant and there are multiple technology Ids, depending on how many are selected in the view. I also save my project details to the project table. I do not save anything to the technology table as it is static (I do not create technologies on my Create Project View).
Here is my solution that worked:
Models:
public class Project
{
public int Id { get; set; }
public string Website { get; set; }
}
public class Technology
{
public int Id { get; set; }
public string Name { get; set; }
public bool IsActive { get; set; }
}
public class ProjectTechnologyMap
{
public int Id { get; set; }
public int ProjectId { get; set; }
public int TechnologyId { get; set; }
}
ViewModel:
public class ProjectTechnologyViewModel
{
public List<Technology> Technologies { get; set; }
public Project Projects { get; set; }
public ProjectTechnologyMap ProjectTechnologyMapping { get; set; }
public ProjectTechnologyViewModel()
{
Projects = new Project();
ProjectTechnologyMapping = new ProjectTechnologyMap();
}
}
DB Context:
public class NovaDB : DbContext
{
public NovaDB(): base("DefaultConnection")
{
}
public DbSet<Technology> Technologies { get; set; }
public DbSet<Project> Projects { get; set; }
public DbSet<ProjectTechnologyMap> ProjectTechnologyMappings { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
}
Controller:
public ActionResult Create()
{
var technologies = from t in _db.Technologies
orderby t.Name
where t.IsActive
select t;
var viewModel = new ProjectTechnologyViewModel();
viewModel.Technologies = technologies.ToList();
return View(viewModel);
}
[HttpPost]
public ActionResult Create(ProjectTechnologyViewModel viewModel)
{
if (ModelState.IsValid)
{
var proj = new Project
{
LaunchDate = viewModel.Projects.LaunchDate,
ProjectType = viewModel.Projects.ProjectType,
ServiceId = viewModel.Projects.ServiceId,
ShowInOurWork = viewModel.Projects.ShowInOurWork,
Website = viewModel.Projects.Website
};
_db.Projects.AddOrUpdate(proj);
_db.SaveChanges();
var map = new ProjectTechnologyMap();
foreach (var item in viewModel.Technologies)
{
if (item.UsedInProject)
{
map.TechnologyId = item.Id;
map.ProjectId = proj.Id;
_db.ProjectTechnologyMappings.Add(map);
_db.SaveChanges();
}
}
}
return RedirectToAction("Index", "Project");
}
Loop in my View to handle the list of technologies:
#for (var i = 0; i < Model.Technologies.Count; i++)
{
<div class="form-group">
#Html.LabelFor(x => x.Technologies[i].Name, Model.Technologies[i].Name, new {#class = "control-label col-md-2"})
<div class="col-md-10">
<div class="checkbox">
#Html.EditorFor(x => x.Technologies[i].UsedInProject)
#Html.HiddenFor(x => x.Technologies[i].Id)
</div>
</div>
</div>
}

ASP.NET MVC5 - Validate against other table

Using VS2013 and building my first MVC app with EF6 (database first). I have a jobs table and a related items table (there can be millions of records per job). I need to give the user a way to export a subset of items (e.g. item 1,000 - 10,000).
So my controller contains a get method that opens a new view where they can enter the start and end values.
I want to default these to the min and max values from the items table and then I need to validate that the two numbers entered exist in the items table.
Here's my view:
#model PSAMVC.Models.Job
#{
ViewBag.Title = "ExportToLake";
}
<h2>ExportToLake</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Job</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
#Html.HiddenFor(model => model.ID)
<div class="form-group">
#Html.LabelFor(model => model.JobNo, "JobNo", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DisplayFor(model => model.JobNo, new { htmlAttributes = new { #class = "form-control" } })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.VersionRef, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DisplayFor(model => model.VersionRef, new { htmlAttributes = new { #class = "form-control" } })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.PSAJobRef, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DisplayFor(model => model.PSAJobRef, new { htmlAttributes = new { #class = "form-control" } })
</div>
</div>
<div class="form-group">
#Html.Label("Start Seq No", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.TextBox("StartSeqNo")
</div>
</div>
<div class="form-group">
#Html.Label("End Seq No", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.TextBox("EndSeqNo")
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Export" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
How/where would I enter the code to validate the two numbers against the items table?
I would think that doing in the view is the best place as the user would get immediate feedback and I can code the controller method knowing it will always be passed valid values.
I could add a view to Db that contains the job no and min and max item no, but it seems like a bit of a hack.
TIA
Mark
Update: here's my Jobs model:
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated from a template.
//
// Manual changes to this file may cause unexpected behavior in your application.
// Manual changes to this file will be overwritten if the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace PSAMVC.Models
{
using System;
using System.Collections.Generic;
public partial class Job
{
public Job()
{
this.Items = new HashSet<Item>();
this.Reprints = new HashSet<Reprint>();
this.Scans = new HashSet<Scan>();
this.LabelTypes = new HashSet<LabelType>();
}
public int ID { get; set; }
public string JobNo { get; set; }
public string VersionRef { get; set; }
public string PSAJobRef { get; set; }
public int TotalCopies { get; set; }
public int CopiesPerBundle { get; set; }
public int CopiesPerCarton { get; set; }
public int CopiesPerMasterCarton { get; set; }
public Nullable<int> CopiesPerPallet { get; set; }
public int CardType { get; set; }
public string CardTitle { get; set; }
public string CardMMYY { get; set; }
public string StartSerialNo { get; set; }
public int StartBundleNo { get; set; }
public int StartCartonNo { get; set; }
public Nullable<int> StartMasterCartonNo { get; set; }
public Nullable<int> StartPalletNo { get; set; }
public string ProductUPC { get; set; }
public string PackagingUPC { get; set; }
public bool PreProcessed { get; set; }
public bool Completed { get; set; }
public Nullable<int> FormatFileID { get; set; }
public bool UseDummyBarcode { get; set; }
public bool Samples { get; set; }
public string PartNo { get; set; }
public string ProductEAN { get; set; }
public string PONo { get; set; }
public string ImportedFileList { get; set; }
public bool ExportedToLake { get; set; }
public Nullable<int> TotalPalletsOverride { get; set; }
public virtual CardType CardType1 { get; set; }
public virtual FormatFile FormatFile { get; set; }
public virtual ICollection<Item> Items { get; set; }
public virtual SG360JobNos SG360JobNos { get; set; }
public virtual ICollection<Reprint> Reprints { get; set; }
public virtual ICollection<Scan> Scans { get; set; }
public virtual ICollection<LabelType> LabelTypes { get; set; }
}
}
and here's my jobs controller
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Linq;
using System.Net;
using System.Web;
using System.Web.Mvc;
using PSAMVC.Models;
using System.Data.SqlClient;
using System.Configuration;
namespace PSAMVC.Controllers
{
public class JobsController : Controller
{
private PSAMVCEntities db = new PSAMVCEntities();
// GET: Jobs
public ActionResult Index()
{
var jobs = db.Jobs.Include(j => j.CardType1).Include(j => j.FormatFile).Include(j => j.SG360JobNos);
return View(jobs.ToList());
}
// GET: Jobs/Details/5
public ActionResult Details(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Job job = db.Jobs.Find(id);
if (job == null)
{
return HttpNotFound();
}
return View(job);
}
// GET: Jobs/Create
public ActionResult Create()
{
ViewBag.CardType = new SelectList(db.CardTypes, "ID", "Description");
ViewBag.FormatFileID = new SelectList(db.FormatFiles, "ID", "Name");
ViewBag.JobNo = new SelectList(db.SG360JobNos, "JobNo", "JobNo");
return View();
}
// GET: CreateBundlesAndCartons
public ActionResult CreateBandC(Int32 id)
{
string ReturnMessage;
ReturnMessage = "";
using (SqlConnection connection = new SqlConnection())
{
//string connectionStringName = this.DataWorkspace.CooperData.Details.Name;
connection.ConnectionString =
ConfigurationManager.ConnectionStrings["PSAContext"].ConnectionString;
string procedure = "PSA.dbo.CreateBundlesAndCartons";
using (SqlCommand command = new SqlCommand(procedure, connection))
{
command.CommandType = CommandType.StoredProcedure;
command.CommandTimeout = 300;
command.Parameters.Add(
new SqlParameter("#JobID", id));
SqlParameter ErrorString = new SqlParameter("#ErrorString", ReturnMessage);
ErrorString.Direction = ParameterDirection.Output;
ErrorString.Size = 4000;
command.Parameters.Add(ErrorString);
connection.Open();
command.ExecuteNonQuery();
// Save Outout Param
ReturnMessage = ErrorString.Value.ToString();
#ViewBag.Results = ReturnMessage;
}
}
//return Content("You requested the to create bundles and cartons for job ID " + id.ToString() + "<br />Result: " + ReturnMessage + "<br /> Return to Jobs");
return PartialView("_SPResults");
}
// GET: Jobs/ExportToLake/5
public ActionResult ExportToLake(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Job job = db.Jobs.Find(id);
if (job == null)
{
return HttpNotFound();
}
ViewBag.JobNo = new SelectList(db.SG360JobNos, "JobNo", "JobNo", job.JobNo);
return View(job);
}
// GET: ExportToLake1
public ActionResult ExportToLake1(Int32 id, Int64 StartSeqNo, Int64 EndSeqNo, Boolean ReverseOrder, String FileNameSuffix)
{
string ReturnMessage;
ReturnMessage = "";
using (SqlConnection connection = new SqlConnection())
{
//string connectionStringName = this.DataWorkspace.CooperData.Details.Name;
connection.ConnectionString =
ConfigurationManager.ConnectionStrings["PSAContext"].ConnectionString;
string procedure = "PSA.dbo.ExportToLakeBulk";
using (SqlCommand command = new SqlCommand(procedure, connection))
{
command.CommandType = CommandType.StoredProcedure;
command.CommandTimeout = 1200;
command.Parameters.Add(
new SqlParameter("#JobID", id));
command.Parameters.Add(
new SqlParameter("#ReverseOrder", ReverseOrder));
command.Parameters.Add(
new SqlParameter("#StartSeqNo", StartSeqNo));
command.Parameters.Add(
new SqlParameter("#EndSeqNo", EndSeqNo));
command.Parameters.Add(
new SqlParameter("#Suffix", FileNameSuffix));
SqlParameter ErrorString = new SqlParameter("#ErrorString", ReturnMessage);
ErrorString.Direction = ParameterDirection.Output;
ErrorString.Size = 4000;
command.Parameters.Add(ErrorString);
connection.Open();
command.ExecuteNonQuery();
// Save Outout Param
ReturnMessage = ErrorString.Value.ToString();
#ViewBag.Results = ReturnMessage;
}
}
//return Content("You requested the to create bundles and cartons for job ID " + id.ToString() + "<br />Result: " + ReturnMessage + "<br /> Return to Jobs");
return PartialView("_SPResults");
}
// POST: Jobs/ExportToLake
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult ExportToLake2([Bind(Include = "ID,StartSeqNo,EndSeqNo,ReverseOrder")] Job job)
{
if (ModelState.IsValid)
{
//db.Jobs.Add(job);
//db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.CardType = new SelectList(db.CardTypes, "ID", "Description", job.CardType);
ViewBag.FormatFileID = new SelectList(db.FormatFiles, "ID", "Name", job.FormatFileID);
ViewBag.JobNo = new SelectList(db.SG360JobNos, "JobNo", "JobNo", job.JobNo);
return View(job);
}
// POST: Jobs/Create
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "ID,JobNo,VersionRef,PSAJobRef,TotalCopies,CopiesPerBundle,CopiesPerCarton,CopiesPerMasterCarton,CopiesPerPallet,CardType,CardTitle,CardMMYY,StartSerialNo,StartBundleNo,StartCartonNo,StartMasterCartonNo,StartPalletNo,ProductUPC,PackagingUPC,PreProcessed,Completed,FormatFileID,UseDummyBarcode,Samples,PartNo,ProductEAN,PONo,ImportedFileList,ExportedToLake,TotalPalletsOverride")] Job job)
{
if (ModelState.IsValid)
{
db.Jobs.Add(job);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.CardType = new SelectList(db.CardTypes, "ID", "Description", job.CardType);
ViewBag.FormatFileID = new SelectList(db.FormatFiles, "ID", "Name", job.FormatFileID);
ViewBag.JobNo = new SelectList(db.SG360JobNos, "JobNo", "JobNo", job.JobNo);
return View(job);
}
// GET: Jobs/Edit/5
public ActionResult Edit(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Job job = db.Jobs.Find(id);
if (job == null)
{
return HttpNotFound();
}
ViewBag.CardType = new SelectList(db.CardTypes, "ID", "Description", job.CardType);
ViewBag.FormatFileID = new SelectList(db.FormatFiles, "ID", "Name", job.FormatFileID);
ViewBag.JobNo = new SelectList(db.SG360JobNos, "JobNo", "JobNo", job.JobNo);
return View(job);
}
// POST: Jobs/Edit/5
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit([Bind(Include = "ID,JobNo,VersionRef,PSAJobRef,TotalCopies,CopiesPerBundle,CopiesPerCarton,CopiesPerMasterCarton,CopiesPerPallet,CardType,CardTitle,CardMMYY,StartSerialNo,StartBundleNo,StartCartonNo,StartMasterCartonNo,StartPalletNo,ProductUPC,PackagingUPC,PreProcessed,Completed,FormatFileID,UseDummyBarcode,Samples,PartNo,ProductEAN,PONo,ImportedFileList,ExportedToLake,TotalPalletsOverride")] Job job)
{
if (ModelState.IsValid)
{
db.Entry(job).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.CardType = new SelectList(db.CardTypes, "ID", "Description", job.CardType);
ViewBag.FormatFileID = new SelectList(db.FormatFiles, "ID", "Name", job.FormatFileID);
ViewBag.JobNo = new SelectList(db.SG360JobNos, "JobNo", "JobNo", job.JobNo);
return View(job);
}
// GET: Jobs/Delete/5
public ActionResult Delete(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Job job = db.Jobs.Find(id);
if (job == null)
{
return HttpNotFound();
}
return View(job);
}
// POST: Jobs/Delete/5
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public ActionResult DeleteConfirmed(int id)
{
Job job = db.Jobs.Find(id);
db.Jobs.Remove(job);
db.SaveChanges();
return RedirectToAction("Index");
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
db.Dispose();
}
base.Dispose(disposing);
}
}
}
Firstly the server side code should not assume that the values being passed are valid. Always validate the values and handle errors correctly. Client side validation can be bypassed.
In terms of providing instant feedback, one approach is to have an action on a controller that accepts the value to validate as a parameter and returns json containing whether the value was valid and if not the error.
This action can then be called on the input fields blur event or change even providing close to real time feedback on whether the values are valid.
Another approach is to have the valid values determined during the page rendering process and embedded into the client side validation framework if you have one (or use custom JS).
Client Code
function performValidate(data, url) {
var result = $.ajax({
type: "POST",
url: url,
data: data,
success: function (data) {
if (!data.success) {
//HandleIncorrectValue
}
//HandleCorrectValue
},
error: function (data) {
//HandleError
}
});
Controller Code
[HttpPost]
public ActionResult Validate(int value)
{
var response = ValidateValue(value);
return Json(new { success = response.Success, message = response.Message });
}

Create ActionResult for save throws error saying The model item passed into the dictionary is of type

Although this error is very common in the forum, but i am not able to understand how to fix it in my project. I am new to MVC framework.
View code:-
#model ClassifiedProject.Models.CreateAdvertVM
<div class="editor-label">#Html.LabelFor(model => model.AdvTitle) <i>(E.g. Old Samsung Galaxy Tab 2)</i></div>
<div class="editor-field">
#Html.EditorFor(model => model.AdvTitle)
#Html.ValidationMessageFor(model => model.AdvTitle)
</div>
<div class="editor-label">#Html.LabelFor(model => model.AdvDescription)</div>
<div class="editor-field">
#Html.TextAreaFor(model => model.AdvDescription)
#Html.ValidationMessageFor(model => model.AdvDescription)
</div>
<div class="editor-label">#Html.Label("Advertisement Category")</div>
<div class="editor-label">
#Html.DropDownListFor(model => model.SelectedCategoryId, Model.Categories, new { #class = "ddlcs" })
#Html.ValidationMessageFor(model => model.SelectedCategoryId)
</div>
<p><input type="submit" value="Save" /></p>
Controller code of Save button actionresult:-
[HttpPost]
public ActionResult Create(TR_ADVERTISEMENT tr_advert)
{
if (ModelState.IsValid)
{
tr_advert.CreatedDate = tr_advert.ModifiedDate = DateTime.Now;
if (tr_advert.IsPriceOnRequest)
{
tr_advert.CurrencyID = 0;
tr_advert.Price = 0;
}
db.ADVERTISEMENT.Add(tr_advert);
db.SaveChanges();
return RedirectToAction("Index");
}
Controller code for the form in render stage:-
// GET: /Advert/Create
public ActionResult Create()
{
var model = new CreateAdvertVM();
ViewBag.Message = "Post New Advertisement.";
////Render Category DDL
var cat = from s in db.CategoryDbSet
where s.IsActive == true
orderby s.CatName
select new { s.CatID, s.CatName };
var catListItems = cat.ToList().Select(c => new SelectListItem
{
Text = c.CatName,
Value = c.CatID.ToString()
}).ToList();
catListItems.Insert(0, new SelectListItem { Text = "[--Select the category--]", Value = "" });
model.Categories = catListItems;
return View(model);
ViewModel inherited from EF class:-
[NotMapped]
public class CreateAdvertVM : TR_ADVERTISEMENT
{
[DisplayName("Category")]
[Required]
public int? SelectedCategoryId { get; set; }
public IEnumerable<SelectListItem> Categories { get; set; }
}
EF Model:-
public class TR_ADVERTISEMENT
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int AdvID { get; set; }
[Required]
[DisplayName("Sub Category")]
public int SubCatID { get; set; }
public int CurrencyID { get; set; }
[DisplayName("Price on request")]
public bool IsPriceOnRequest { get; set; }
[DisplayName("Posted Date")]
[DisplayFormat (DataFormatString="{0:dd-MM-yyyy}")]
public Nullable<System.DateTime> CreatedDate { get; set; }
public Nullable<System.DateTime> ModifiedDate { get; set; }
}
On the save button click, i have to save the data into the tr_advertisement table using the EF model.
Please suggest the solution to this problem.
It is the model type you are passing into your Create ActionMethod.
public ActionResult Create(TR_ADVERTISEMENT tr_advert)
should be
public ActionResult Create(CreateAdvertVM tr_advert)
I am assuming that if your model is not valid, you are passing it back further down in your action result (which you are not showing), such as
Return View(tr_advert)
But, you are passing the wrong model type at that point for that view.
EDIT
I would also update your view model so that instead of inheriting from the EF class, simply include the EF class as a property.
public class CreateAdvertVM
{
[DisplayName("Category")]
[Required]
public int? SelectedCategoryId { get; set; }
public IEnumerable<SelectListItem> Categories { get; set; }
public TR_ADVERTISEMENT tr_advert{get;set;}
}
This will make it so that your save code in the Create method can still be used with only minor modifications
[HttpPost]
public ActionResult Create(CreateAdvertVM model)
{
if (ModelState.IsValid)
{
model.tr_advert.CreatedDate = model.tr_advert.ModifiedDate = DateTime.Now;
if (model.tr_advert.IsPriceOnRequest)
{
model.tr_advert.CurrencyID = 0;
model.tr_advert.Price = 0;
}
db.ADVERTISEMENT.Add(model.tr_advert);
db.SaveChanges();
return RedirectToAction("Index");
}

Resources