ASP.NET MVC3 submit post passing a Dictionary to Controller - asp.net-mvc

I have a dictionary being used. And when the "submit" is hit, how do I also pass the dictionary with the values in it to the [HttpPost] controller method?
Currently in the [HttpPost] method, the DummyDictionary is empty, how would I fix this?
Thanks!
MODEL
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using DummyMVC.Objects;
namespace DummyMVC.Models
{
public class TheModel
{
public TheObject Obj { get; set; }
public Dictionary<string, TheObject> DummyDictionary { get; set; }
}
}
CONTROLLER
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using DummyMVC.Models;
using DummyMVC.Objects;
namespace DummyMVC.Controllers
{
public class DummyController : Controller
{
//
// GET: /Dummy/
[HttpGet]
public ActionResult Index()
{
TheModel m = new TheModel();
m.Obj = new Objects.TheObject();
TheObject a_obj = new TheObject();
a_obj.Name = "Joe";
m.DummyDictionary = new Dictionary<string, Objects.TheObject>();
m.DummyDictionary.Add("VT", a_obj);
return View(m);
}
[HttpPost]
public ActionResult Index(TheModel model)
{
// HERE THE DICTIONARY is EMPTY, where all the form values should exist.
string test = "";
return View(model);
}
}
}
VIEW
#model DummyMVC.Models.TheModel
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
#using (Html.BeginForm())
{
#Html.HiddenFor(m => m.DummyDictionary);
#Html.LabelFor(m => m.DummyDictionary["VT"].Name)
#Html.TextBoxFor(m => m.DummyDictionary["VT"].Value)<br />
#Html.TextBoxFor(m => m.DummyDictionary["VT"].Token, new { #Value = Model.DummyDictionary["VT"].Token, style = "display:none;" })
<input type="submit" class="submit_button" /><br />
}
In the view I am using #Html.HiddenFor(m => m.DummyDictionary) to try to pass the dictionary over to the post method, but the dictionary is just empty. Without this #Html.HiddenFor the Dictionary in the post method is null.
Thank you so much for the assistance I appreciate it!
UPDATE
TheObject
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace DummyMVC.Objects
{
public class TheObject
{
public string Name { get; set; }
public string Value { get; set; }
public string Token { get; set; }
}
}

It's not pretty but it works. Remember to include all properties of TheObject, if not visible then hidden so they get posted. Would probably be a good idea to make a helper for this.
#model MvcApplication1.Models.TheModel
#using (Html.BeginForm())
{
#Html.LabelFor(m => m.DummyDictionary["VT"].Name)
#Html.Hidden("DummyDictionary[VT].Name",Model.DummyDictionary["VT"].Name)
#Html.Hidden("DummyDictionary[VT].Token", Model.DummyDictionary["VT"].Token)
#Html.TextBox("DummyDictionary[VT].Value", Model.DummyDictionary["VT"].Value)
<input type="submit" class="submit_button" /><br />
}
Controller
[HttpGet]
public ActionResult Index()
{
TheModel m = new TheModel();
m.Obj = new TheObject();
TheObject a_obj = new TheObject();
a_obj.Name = "Joe";
m.DummyDictionary = new Dictionary<string, TheObject>();
m.DummyDictionary.Add("VT", a_obj);
return View(m);
}
[HttpPost]
public ActionResult Index(TheModel model)
{
// HERE THE DICTIONARY is EMPTY, where all the form values should exist.
string test = "";
return View(model);
}

Related

Facing an issue regarding compiling my project

Can anyone help me regarding the below issue I'm facing in the attached image. I'm trying to go to this url: http://localhost:49849/Customers but I couldn't. Thanks in advance... Just to let you know I;m following Mosh's Cource.
enter image description here
Here is the Model code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel.DataAnnotations; //this is a namespace
namespace Vidly2.Models
{
public class Customers
{
public int id { get; set; }
[Required] // we cal changing the conventions dataannotations
[StringLength(255)]
public string name { get; set; }
public bool IsSubscribedToNewsletter { get; set; }
public MembershipType MembershipType { get; set; } // we call it navigation property because it allows us to navigate to another type
public byte MembershipTypeId { get; set; } //Fk
}
}
here is the Controller code:
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using Vidly2.Models;
namespace Vidly2.Controllers
{
public class CustomersController : Controller
{
public ViewResult Index()
{
var customers = GetCustomers();
return View(customers);
}
public ActionResult Details(int id)
{
var customer = GetCustomers().SingleOrDefault(c => c.id == id);
if (customer == null)
return HttpNotFound();
return View(customer);
}
private IEnumerable<Customers> GetCustomers()
{
return new List<Customers>
{
new Customers { id =1, name = "John Smith" },
new Customers { id =2, name = "Mary Williams" }
};
}
}
}
and here is the view code which has the mentioned error regarding compiling the project:
#using System.Web.Mvc.Html;
#model IEnumerable<Vidly2.Models.Customers>
#*
Note: I've set the model for this view to IEnumerable<Customer>.
This is a simple interface implemented by the list class. Since
in this view we only want to iterate over this list, and we don't
need any of the operations in the List class (eg Add, Remove, etc),
it's better to use the IEnumerable interface, which allows use to
iterate over the list. If in the future, we replace the List with a
different data structure, as long as it is enumerable, our view code
will remain unchanged.
*#
#{
ViewBag.Title = "Customers";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Customers</h2>
#if (!Model.Any())
{
<p>We don't have any customers yet.</p>
}
else
{
<table class="table table-bordered table-hover">
<thead>
<tr>
<th>Customer</th>
</tr>
</thead>
<tbody>
#foreach (var customer in Model)
{
<tr>
<td>#Html.ActionLink(customer.Name, "Details", "Customers", new { id = customer.id }, null)</td>
</tr>
}
</tbody>
</table>
}
You have property mismatch for name, Like in your model it is in small case name, but in view you are using customer.Name which should be customer.name
#Html.ActionLink(customer.name, "Details", ...

How to post view model to controller

I am trying to create a view that takes a view model, simply has an int property and a list of child model, with int; string; string properties.
What i am trying to do is everytime user clicks an "add line" button, i am creating a new child model in my view model list, letting user edit the properties and then want to post back to my controller but no matter what, it is always empty.
I know this must be simple but has me stumped for hours today? Is there some magic that needs to happen?
Any help appreciated.
My Controller:
using System.Web.Mvc;
using WebApplication1.Models;
namespace WebApplication1.Controllers
{
public class EmployeeUploadController : Controller
{
// GET: EmployeeUpload
public ActionResult EmployeeUpload()
{
var vm = new EmployeeBulkUpload { UploadedBy = 12345 };
vm.Employees.Add(new EmployeeBulkUploadItem { Id = 1, JobTitle = "Labourer", Name = "Jimmy" });
return View(vm);
}
[HttpPost]
[ActionName("EmployeeUpload")]
public ActionResult EmployeeUploadPost(EmployeeBulkUpload vm)
{
return View(vm);
}
}
}
My Model:
using System.Collections.Generic;
namespace WebApplication1.Models
{
public class EmployeeBulkUpload
{
public EmployeeBulkUpload()
{
Employees = new List<EmployeeBulkUploadItem>();
}
public int UploadedBy { get; set; }
public List<EmployeeBulkUploadItem> Employees { get; set; }
}
public class EmployeeBulkUploadItem
{
public int Id { get; set; }
public string Name { get; set; }
public string JobTitle { get; set; }
}
}
My "Container" view:
#using WebApplication1.Models
#model WebApplication1.Models.EmployeeBulkUpload
#{
ViewBag.Title = "EmployeeUpload";
}<div>
#using (Html.BeginForm("EmployeeUpload", "EmployeeUpload", FormMethod.Post))
{
<h2>EmployeeUpload</h2>
<button>Add New</button>
foreach(EmployeeBulkUploadItem emp in Model.Employees)
{
Html.RenderPartial("_EmployeeUploadItem", emp);
}
<input type="submit" name="SaveButton" value="Save" />
}
</div>
My Item Partial view:
#model WebApplication1.Models.EmployeeBulkUploadItem
<li>
#Html.LabelFor(x => x.Id)
#Html.EditorFor(x => x.Id)
#Html.LabelFor(x => x.Name)
#Html.EditorFor(x => x.Name)
#Html.LabelFor(x => x.JobTitle)
#Html.EditorFor(x => x.JobTitle)
</li>
I can load with one record and post straight back but is always empty in my Controller EmployeeUploadPost method?

ASP.NET MVC ModelState has error for IEnumeration<SelectListItem> in view model

In an ASP.NET MVC 5 web site, I am populating a drop down in a view and getting the value back in the POST action. However, ModelState.IsValid is always false. In investigating why, I found that there is an error for the IEnumerable<SelectListItem> property, which contains the data for the drop down.
Here is the exception from the ModelState for the IEnumerable<SelectListItem>property:
The parameter conversion from type 'System.String' to type 'System.Web.Mvc.SelectListItem' failed because no type converter can convert between these types.
From what I've read, it looks like I am using the view model correctly and setting up the drop down correctly.
Asp.net mvc ModelState validity when using dropdownlist
https://forums.asp.net/t/1715908.aspx
This is inconvenient because ModelState.IsValid is checked elsewhere for error handling, but in the POST action AvailableStates is irrelevant. Any ideas as to why the IEnumerable<SelectListItem> property always has this error?
I made a simple web site that replicates the issue.
View Model
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Web.Mvc;
namespace SandboxAspNet.Models
{
public class HomeViewModel
{
[Required(ErrorMessage = "Please select a state.")]
[Display(Name = "State")]
public string SelectedState { get; set; }
public IEnumerable<SelectListItem> AvailableStates { get; set; }
}
}
Controller
using System.Collections.Generic;
using System.Web.Mvc;
using SandboxAspNet.Models;
namespace SandboxAspNet.Controllers
{
public class HomeController : Controller
{
[HttpGet]
public ActionResult Index()
{
var model = new HomeViewModel()
{
AvailableStates = GetAvailableStates()
};
return View(model);
}
[HttpPost]
public ActionResult Submit(HomeViewModel model)
{
if (!ModelState.IsValid)
{
model.AvailableStates = GetAvailableStates();
return View("Index", model);
}
return View("Success");
}
// Generate some dummy data for the drop down
private static IEnumerable<SelectListItem> GetAvailableStates()
{
return new List<SelectListItem>()
{
new SelectListItem()
{
Text = "Alabama",
Value = "AL"
},
new SelectListItem()
{
Text = "Alaska",
Value = "AK",
},
new SelectListItem()
{
Text = "Arizona",
Value = "AZ",
},
new SelectListItem()
{
Text = "Arkanasas",
Value = "AR"
}
};
}
}
}
View
#model SandboxAspNet.Models.HomeViewModel
#{
ViewBag.Title = "Home Page";
}
#using (Ajax.BeginForm("Submit", "Home", Model, null))
{
#Html.ValidationSummary()
<div>
<strong>#Html.LabelFor(model => model.SelectedState)</strong>
#Html.DropDownListFor(model => model.SelectedState, Model.AvailableStates, "--Select a State---", new { #type = "text", #style = "width:100%;", #class = "form-control" })
#Html.ValidationMessageFor(model => model.SelectedState)
</div>
<div>
<button type="submit">Submit</button>
</div>
}
Your third parameter to Ajax.BeginForm() is wrong. That parameter is for routeValues.
public static MvcForm BeginForm(
this AjaxHelper ajaxHelper,
string actionName,
string controllerName,
object routeValues,
AjaxOptions ajaxOptions
)
You can possibly just make the third and four parameter null if you don't need to do anything more advanced.
#using (Ajax.BeginForm("Submit", "Home", Model, null))

Composite model not binding mvc 3

I have created two models, Student and School and a composite model, StudentSchool. I am using two different partiel views to create one the Student and the other the School. However, in my controller, I am getting null values for both the Student and School. Below is my code:
Student:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace LayoutProject.Models
{
public class Student
{
public int studentID { get; set; }
public String firstname { get; set; }
public String lastname { get; set; }
public int year { get; set; }
}
}
School:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace LayoutProject.Models
{
public class School
{
public int schoolID { get; set; }
public String name { get; set; }
public String add { get; set; }
}
}
Composite model, StudentSchool:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace LayoutProject.Models
{
public class StudentSchool
{
public Student student { get; set; }
public School school { get; set; }
}
}
PartielViewStudent:
#model LayoutProject.Models.Student
<h4>Student</h4>
#Html.LabelFor(d=>d.studentID) : #Html.TextBoxFor(d=>d.studentID)
<br />
#Html.LabelFor(d=>d.firstname) : #Html.TextBoxFor(d=>d.firstname)
<br />
#Html.LabelFor(d=>d.lastname) : #Html.TextBoxFor(d=>d.lastname)
<br />
#Html.LabelFor(d=>d.year) : #Html.TextBoxFor(d=>d.year)
<br />
PartialViewSchool:
#model LayoutProject.Models.School
<h4>School</h4>
#Html.LabelFor(d=>d.schoolID) : #Html.TextBoxFor(d=>d.schoolID)
<br />
#Html.LabelFor(d=>d.name) : #Html.TextBoxFor(d=>d.name)
<br />
#Html.LabelFor(d=>d.add) : #Html.TextBoxFor(d=>d.add)
<br />
The View:
#{
ViewBag.Title = "StudentSchool";
}
<h2>StudentSchool</h2>
<form action="/Home/CreateStudentSchools" method="post">
#using (Html.BeginForm())
{
#Html.Partial("_PartialViewStudent")
#Html.Partial("_PartialViewSchool")
}
<input id="createSD" type="submit" value="Submit"/>
</form>
The controller:
[HttpPost]
public ActionResult CreateStudentSchools(StudentSchool ss)
{
return View("CreateStudentSchool");
}
Any idea what I might be missing here? Been with this since 4 days.
Move you 'partial' views into the /Views/Shared/EditorTemplates folder and rename them to Student.cshtml and School.cshtml respectively (to match the names of the classes). Then in the main view use
#using (Html.BeginForm())
{
#Html.EditorFor(m => m.Student)
#Html.EditorFor(m => m.School)
}
The inputs your generating will now contain the correct name attribute for binding to your view model, for example name="Student.studentID" instead of the current name="studentID"
Note: As an alternative, you can pass the HtmlFieldPrefix to a Partial as indicated in this answer.
Its not a good idea if you provide the two partial views with different models and combining in one model.You have to pass the reference of the composite model to your partial views.
#using (Html.BeginForm())
{
#Html.Partial("_PartialViewStudent",Model.student)
#Html.Partial("_PartialViewSchool",Model.school)
}
This will work fine as with this approach as everything in the form is strictly typed.
In partial views also you have to specify models as
#model LayoutProject.Models.StudentSchool.student
#model LayoutProject.Models.StudentSchool.school
I am not sure about your [httpget] create method but it should be like
[HttpGet]
public ActionResult CreateStudentSchools(StudentSchool ss)
{
var studentsc=new StudentSchool()
{
student=new Student(),
school=new School()
}
return View("CreateStudentSchool",studentsc);
}

How to create MVC 4 #Html.TextBox type="file"?

I need to add the following field at my form
<input type="file" class="input-file" />
I create model and describe this field (the last field)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace CorePartners_Site2.Models
{
public class FeedbackForm
{
public string Name { get; set; }
public string Email { get; set; }
public string Phone { get; set; }
public string Company { get; set; }
public string AdditionalInformation { get; set; }
public HttpPostedFileBase ProjectInformation { get; set; }
}
}
and create
#Html.TextBox(null, null, new { type="file", #class="input-file" })
but it doesnt work, I get some exception.
What's wrong?
Model
public class FeedbackForm
{
public string Name { get; set; }
public string Email { get; set; }
public string Phone { get; set; }
public string Company { get; set; }
public string AdditionalInformation { get; set; }
public HttpPostedFileBase ProjectInformation { get; set; }
}
View
#model FeedbackForm
#Html.TextBox("Name")
#Html.TextBox("Email")
...
#Html.TextBox("ProjectInformation", null, new { type="file", #class="input-file" })
// submit button
My recommended view (strongly - typed)
#model FeedbackForm
#Html.TextBoxFor(model=>model.Name)
#Html.TextBoxFor(model=>model.Email)
...
#Html.TextBoxFor(model=>model.ProjectInformation, null, new { type="file", #class="input-file" })
// submit button
Controller
[HttpPost]
public ActionResult FeedbackForm(FeedbackForm model)
{
// this is your uploaded file
var file = model.ProjectInformation;
...
return View();
}
MVC is using name convention, so if your textbox and model names match, then MVC will bind your inputs to your model.
I think you are getting a null because you have not specified the enctype in your form tag.
#using (Html.BeginForm("ActionMethodName", "Controller", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
}
A working example always help.
Visit http://www.mindstick.com/Articles/cf1e1dd9-fdba-4617-94f0-407223574447/?Upload%20File%20in%20Asp.Net%20Mvc%204
You can use the below syntax
#Html.TextBoxFor(model=>model.Email, new { #type="file", #class="input-file" })
I solved this problem using enctype="multipart/form-data"
#using (Html.BeginForm("SalvarEvidencia", "Evidencia", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
...
}
There's nothing wrong with just using the input tag directly in your view. You aren't required to use a helper.
<input type="file" class="input-file" />
Just make sure it's within your BeginForm declaration block.
You need to specify the name of the field. If you don't want a name, nor a value, it's better to just include the field as is in your form.
It doesn't make sense to use a helper, if there's nothing dynamic about it.
#using (Html.BeginForm("Action_Name", "Controller_Name",FormMethod.Post))
{
#Html.TextBoxFor(m => m.Email, new {#class = "text_field"})
#Html.ValidationMessageFor(m => m.Email)
}

Resources