Should be an easy question to answer.
I am trying to create an object in a view. The class that contains the object consists of a User class and a password.
When I click on the submit button, the Controller picks up null values for Password and User.
See below the Container class, the Controller and the View;
public class UserExtended
{
public UserITOC User { get; set; }
public string Password { get; set; }
}
[Authorize]
public ActionResult Create()
{
return View(new UserExtended());
}
//
// POST: /Dinners/Create
[Authorize(Roles = "Administrator")]
[HttpPost]
public ActionResult Create(UserExtended user)
{
if (ModelState.IsValid)
{
// Create user in the User datatable
SqlUsersRepository sqlRepository = new SqlUsersRepository();
ITOCEntities db = new ITOCEntities();
db.UserITOCs.AddObject(user.User);
// Create user as an authenticated user within the Reader role.
int i = user.User.EmailAddress.IndexOf('#') - 1;
string userName = user.User.EmailAddress.Substring(0, i);
string email = user.User.EmailAddress;
Membership.CreateUser(userName, user.Password, email);
Roles.AddUserToRole(userName, "Reader"); // Automatically assigned as a Reader
}
return View(new UserExtended());
}
" %>
Create
<h2>Create</h2>
<% using (Html.BeginForm()) {%>
<%: Html.ValidationSummary(true) %>
<fieldset>
<legend>Fields</legend>
<div class="editor-label">
<%: Html.LabelFor(model => model.User.Forename) %>
</div>
<div class="editor-field">
<%: Html.EditorFor(model => model.User.Forename)%>
<%: Html.ValidationMessageFor(model => model.User.Forename)%>
</div>
<div class="editor-label">
<%: Html.LabelFor(model => model.User.Surname) %>
</div>
<div class="editor-field">
<%: Html.EditorFor(model => model.User.Surname)%>
<%: Html.ValidationMessageFor(model => model.User.Surname)%>
</div>
<div class="editor-label">
<%: Html.LabelFor(model => model.User.EmailAddress) %>
</div>
<div class="editor-field">
<%: Html.EditorFor(model => model.User.EmailAddress)%>
<%: Html.ValidationMessageFor(model => model.User.EmailAddress)%>
</div>
<div class="editor-label">
<%: Html.LabelFor(model => model.Password) %>
</div>
<div class="editor-field">
<%: Html.EditorFor(model => model.Password)%>
<%: Html.ValidationMessageFor(model => model.Password) %>
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
<% } %>
<div>
<%: Html.ActionLink("Back to List", "Index") %>
</div>
Extremely simple solution:
Change your action-signature from
public ActionResult Create(UserExtended user)
to
public ActionResult Create(UserExtended UserExtended)
That way the ModelBinder will know how to reassemble the object from Request.
Hope this helps!
I had a very similar problem, but found in my case that I had to match the database table name rather than the type name
Name of the type: NonTradingDay
Database table name: dbo.NonTradingDays (had been pluralized)
Create Method:
[HttpPost]
public ActionResult Create(NonTradingDay NonTradingDays)
{
if (ModelState.IsValid)
{
db.NonTradingDay.Add(NonTradingDays);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(NonTradingDays);
}
I had tried 'NonTradingDay', but still got null; I then looked at the database table name, tried 'NonTradingDays' and the mapping was made (the argument was no longer null).
I think this was because I had the database context as:
public DbSet<NonTradingDay> NonTradingDay { get; set; }
Rather than:
public DbSet<NonTradingDay> NonTradingDays { get; set; }
you are returning a new instance of UserExtended class
return View(new UserExtended());
instead return the object you get as the parameter
return user
Related
I Have controller with following methods:
public ActionResult Create()
{
return View();
}
[Authorize]
[HttpPost]
public ActionResult Create(Tests test)
{
test.CreateDate = DateTime.Now;
test.Author = User.Identity.Name;
TestEntities db = new TestEntities();
db.AddToTests(test);
db.SaveChanges();
return RedirectToAction("CreateQuestion", new { OrderNumber = 1, idTest = test.id });
}
[Authorize]
public ActionResult CreateQuestion(int OrderNumber,int idTest)
{
return View();
}
[Authorize]
[HttpPost]
public ActionResult CreateQuestion(Questions question)
{
TestEntities db = new TestEntities();
db.AddToQuestions(question);
db.SaveChanges();
return RedirectToAction("CreateQuestion", new {id = question.id, t = question.Type});
}
The problem is Create methods works right. It get parameter and adds it to DB. But similar method CreateQuestion displays message about question is null.
What do I wrong?
CreateQuestion view
<%# Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<test.su.Models.Questions>" %>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
Создать вопрос
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2>Создать вопрос</h2>
<% using (Html.BeginForm("CreateQuestion","Test")) { %>
<%: Html.ValidationSummary(true) %>
<fieldset>
<legend>Вопрос</legend>
<div class="editor-label">
<%: Html.LabelFor(model => model.Type,"Тип вопроса") %>
</div>
<% // List of question types
List<SelectListItem> QuestionTypes = new List<SelectListItem>();
SelectListItem t = new SelectListItem();
t.Text = "Вопрос с вариантами ответа (флажки или радиокнопки)";
t.Value = "0";
QuestionTypes.Add(t);
t = new SelectListItem();
t.Text = "Вопрос со свободным ответом (текстовое поле)";
t.Value = "1";
QuestionTypes.Add(t);
%>
<div class="editor-field">
<%: Html.DropDownListFor(model => model.Type, QuestionTypes) %>
<%: Html.ValidationMessageFor(model => model.Type) %>
</div>
<%-- <div class="editor-label">
<%: Html.LabelFor(model => model.OrderNumber,"Порядковый номер вопроса") %>
<%: Html.EditorFor(model => model.OrderNumber) %>
<%: Html.ValidationMessageFor(model => model.OrderNumber) %>
</div>--%>
<div class="editor-label">
<%: Html.LabelFor(model => model.Question,"Текст вопроса") %>
</div>
<div class="editor-field">
<%: Html.TextAreaFor(model => model.Question,2,47,"") %>
<%: Html.ValidationMessageFor(model => model.Question) %>
</div>
<%: Html.HiddenFor(model => model.idTest) %>
<%: Html.ValidationMessageFor(model => model.idTest) %>
<%: Html.HiddenFor(model => model.OrderNumber ) %>
<%: Html.ValidationMessageFor( model => model.OrderNumber) %>
<p>
<input type="submit" value="Далее" />
</p>
</fieldset>
<% } %>
</asp:Content>
This is difficult to figure out without knowing the model. Someone else may provide a better answer, but here is the only thing I can think of for now:
If your Questions model looks like this:
public class Questions
{
int Id {get;set;}
string Name {get;set;}
string Description {get;set;}
}
What you can do, for now, is alter your controller to accept the individual parameters and create the object yourself. This might help you figure out which critical property in your Model is missing.
public ActionResult CreateQuestion(string Name, string Description)
{
//make the entity yourself
Questions newQuestion = new Questions()
{
Name = Name,
Description = Description
}
//your other code here
}
Now normally MVC is smart enough to bind your individual values in your form (view) to your model, but some critical value is missing and causing you issue. Once you've figured out what that is, you can actually restore your controller back to accepting only a Questions object.
Sorry I couldn't help you more.
Good Luck.
I'd like to know how to change the display name of a model, and customize error messages in Entity Framework. I tried the following but it didn't work.
[Required(ErrorMessage = "Required .... :")]
[Display(Name = "Name Agency : ")]
[EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=false)]
[DataMemberAttribute()]
public global::System.String Nag
{
get
{
//code
}
set
{
//code
}
}
This is the code behind my form that adds data into my database. I've omitted irrelevant lines.
<% using (Html.BeginForm("addcar", "Agence", FormMethod.Post, new { #class = "search_form" }))
{ %>
<%: Html.ValidationSummary(true) %>
<div class="editor-label">
<%: Html.LabelFor(model => model.Dmcv) %>
</div>
<div class="editor-field">
<%: Html.EditorFor(model => model.Dmcv) %>
<%: Html.ValidationMessageFor(model => model.Dmcv) %>
</div>
<div class="editor-label">
<%: Html.LabelFor(model => model.Puisv) %>
</div>
<div class="editor-field">
<%: Html.EditorFor(model => model.Puisv) %>
<%: Html.ValidationMessageFor(model => model.Puisv) %>
</div>
// Similaire code
<p>
<input type="submit" value="Create" />
</p>
<% } %>
Change [Display(Name = "Name Agency")] to [DisplayName("Name Agency")] instead.
First you need to reference this:
using System.ComponentModel.DataAnnotations;
For changing the display name of the column, actually [Display(Name="Name Agency")] is OK. I'm using it in my projects.
For error message
[Required(ErrorMessage="Required...")]
I read that it is possible that this won't work if you are using the entity framework designer because the designer overwrites your changes over and over then you will need to use the metadatatype something like this:
[MetadataType(typeof(MetadataMyClass))]
public partial class myclass
{
}
//data annotations here
public class MetadataMyClass
{
[Required(ErrorMessage = "Required...")]
[Display(Name="Column Name")]
public global:: System.String Nag
{
// ... etc, etc...
}
}
If I add data to table witch has no relationships, it's all good: data is adding. But if table have relationships, this is something wrong
Here is my project, what i mean is, for example AddSt in RouteController.
http://zalil.ru/32249903
Here is controller:
[HttpGet]
public ActionResult AddSt(int RouteId)
{
var routeDetails = (from rd in db.Route
join rdd in db.RouteDetail
on rd.RouteId equals rdd.Route.RouteId ///check
where rd.RouteId == RouteId
select rdd).FirstOrDefault();
return View(routeDetails);
}
[HttpPost]
public ActionResult AddSt(RouteDetail rd)
{
try
{
if (ModelState.IsValid)
{
db.AddToRouteDetail(rd);
db.SaveChanges();
return RedirectToAction("Index");
}
}
catch (Exception e)
{
ModelState.AddModelError("Error!", e);
}
return View();
}
and view:
<% using (Html.BeginForm("AddSt","Route")) {%>
<%= Html.ValidationSummary(true) %>
<fieldset>
<legend>Fields</legend>
<div class="editor-label">
</div>
<div class="editor-field">
<%= Html.TextBoxFor(model => model.Route.RouteId)%>
<%= Html.TextBoxFor(model => model.Station)%>
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
<% } %>
Why I can't write model => model.RouteId ????
What's wrong?
Why TrainSheduleDBEntities table RouteDetail doesn't generate field RouteID ?
You are only selecting RouteDetail (rdd)
So you want model.RouteId
Just stick a debug on the addst action.
Have a look what's in rd.
I'm guessing that there's no valid routeid in it.
I have the following code in my aspx view page:
<% using (Html.BeginForm())
{
%>
<div>
CustomerCode:
<%= Html.TextBoxFor(x=> x.CustomerCode) %>
<%= Html.ValidationMessageFor(x => x.CustomerCode)%>
and this code in my model:
public class MyModel
{
[Required(ErrorMessage="customer code req")]
[StringLength(2,ErrorMessage="must be 2 u idiot")]
public string CustomerCode {get; set;}
Though if I enter more than 2 charachters in the textbox and submit the page, in the controller when I do:
if (ModelState.IsValid)
It always says its valid? What am I missing? I have put this MVC project inside a Web Forms project but the MVC project works fine, its just the validation which is not working, any ideas? Thanks.
Make sure that the controller action accepts the model as parameter:
public ActionResult SomeAction(MyModel model)
{
if (ModelState.IsValid)
{
}
return View();
}
Now if you invoke:
http://example.com/myapp/home/someaction?customercode=123
The model should not be valid.
Hmm, it works for me on a test page with the following
public ActionResult Test()
{
MyModel model = new MyModel();
return View(model);
}
[HttpPost]
public ActionResult Test(MyModel model)
{
if (ModelState.IsValid) { }
return View(model);
}
<% using (Html.BeginForm()) {%>
<%: Html.ValidationSummary(true) %>
<fieldset>
<legend>Fields</legend>
<div class="editor-label">
<%: Html.LabelFor(model => model.CustomerCode) %>
</div>
<div class="editor-field">
<%: Html.TextBoxFor(model => model.CustomerCode) %>
<%: Html.ValidationMessageFor(model => model.CustomerCode) %>
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
<% } %>
public class MyModel
{
[Required(ErrorMessage = "customer code req")]
[StringLength(2, ErrorMessage = "must be 2 u idiot")]
public string CustomerCode { get; set; }
}
I'm trying to add a file upload control to my ASP.NET MVC 2 form but after I select a jpg and click Save, it gives the following error:
The input is not a valid Base-64 string as it contains a non-base 64 character, more than two padding characters, or a non-white space character among the padding characters.
Here's the view:
<% using (Html.BeginForm("Save", "Developers", FormMethod.Post, new {enctype = "multipart/form-data"})) { %>
<%: Html.ValidationSummary(true) %>
<fieldset>
<legend>Fields</legend>
<div class="editor-label">
Login Name
</div>
<div class="editor-field">
<%: Html.TextBoxFor(model => model.LoginName) %>
<%: Html.ValidationMessageFor(model => model.LoginName) %>
</div>
<div class="editor-label">
Password
</div>
<div class="editor-field">
<%: Html.Password("Password") %>
<%: Html.ValidationMessageFor(model => model.Password) %>
</div>
<div class="editor-label">
First Name
</div>
<div class="editor-field">
<%: Html.TextBoxFor(model => model.FirstName) %>
<%: Html.ValidationMessageFor(model => model.FirstName) %>
</div>
<div class="editor-label">
Last Name
</div>
<div class="editor-field">
<%: Html.TextBoxFor(model => model.LastName) %>
<%: Html.ValidationMessageFor(model => model.LastName) %>
</div>
<div class="editor-label">
Photo
</div>
<div class="editor-field">
<input id="Photo" name="Photo" type="file" />
</div>
<p>
<%: Html.Hidden("DeveloperID") %>
<%: Html.Hidden("CreateDate") %>
<input type="submit" value="Save" />
</p>
</fieldset>
<% } %>
And the controller:
//POST: /Secure/Developers/Save/
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Save(Developer developer)
{
//get profile photo.
var upload = Request.Files["Photo"];
if (upload.ContentLength > 0)
{
string savedFileName = Path.Combine(
ConfigurationManager.AppSettings["FileUploadDirectory"],
"Developer_" + developer.FirstName + "_" + developer.LastName + ".jpg");
upload.SaveAs(savedFileName);
}
developer.UpdateDate = DateTime.Now;
if (developer.DeveloperID == 0)
{//inserting new developer.
DataContext.DeveloperData.Insert(developer);
}
else
{//attaching existing developer.
DataContext.DeveloperData.Attach(developer);
}
//save changes.
DataContext.SaveChanges();
//redirect to developer list.
return RedirectToAction("Index");
}
Thanks,
Justin
I have recently found a solution for this, although I am now using MVC3 rather than MVC2.
In the Save action, exclude the binary field from the bound object and include a separate HttpPostedFileBase field:
e.g.
public ActionResult Save([Bind(Exclude = "Photo")]Developer developer, HttpPostedFileBase Photo) {...}
Note that you can also do this to avoid having to include the Html.Hidden elements from your View. e.g.:
public ActionResult Save([Bind(Exclude = "Photo,DeveloperID,CreateDate")]Developer developer, HttpPostedFileBase Photo) {...}
You can then use this HttpPostedFileBase object directly rather than needing to access Request.Files.
Personally, I actually store these types of images in the database in an SQL "image" field using this code:
if (Picture != null)
{
if (Picture.ContentLength > 0)
{
byte[] imgBinaryData = new byte[Picture.ContentLength];
int readresult = Picture.InputStream.Read(imgBinaryData, 0, Picture.ContentLength);
Developer.Picture = imgBinaryData;
}
}
Hope this is helpful...
Mark
I just tried your code and was able to upload without any issues. I did not save to the database nor does my Developer class have a Photo property.
namespace MvcApplication5.Controllers
{
public class Developer
{
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime UpdateDate { get; set; }
public int DeveloperID { get; set; }
public string LoginName { get; set; }
public string Password { get; set; }
}
}
Controller
public class DefaultController : Controller
{
//
// GET: /Default/
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult Index()
{
return View();
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Save(Developer developer)
{
//get profile photo.
var upload = Request.Files["Photo"];
if (upload.ContentLength > 0)
{
string savedFileName = Path.Combine(
#"C:\temp",
"Developer_" + developer.FirstName + "_" + developer.LastName + ".jpg");
upload.SaveAs(savedFileName);
}
developer.UpdateDate = DateTime.Now;
if (developer.DeveloperID == 0)
{//inserting new developer.
}
else
{//attaching existing developer.
}
//save changes.
//redirect to developer list.
return RedirectToAction("Index");
}
}
View
<div>
<% using (Html.BeginForm("Save", "Default", FormMethod.Post, new { enctype = "multipart/form-data" }))
{ %>
<%: Html.ValidationSummary(true)%>
<fieldset>
<legend>Fields</legend>
<div class="editor-label">
Login Name
</div>
<div class="editor-field">
<%: Html.TextBoxFor(model => model.LoginName)%>
<%: Html.ValidationMessageFor(model => model.LoginName)%>
</div>
<div class="editor-label">
Password
</div>
<div class="editor-field">
<%: Html.Password("Password")%>
<%: Html.ValidationMessageFor(model => model.Password)%>
</div>
<div class="editor-label">
First Name
</div>
<div class="editor-field">
<%: Html.TextBoxFor(model => model.FirstName)%>
<%: Html.ValidationMessageFor(model => model.FirstName)%>
</div>
<div class="editor-label">
Last Name
</div>
<div class="editor-field">
<%: Html.TextBoxFor(model => model.LastName)%>
<%: Html.ValidationMessageFor(model => model.LastName)%>
</div>
<div class="editor-label">
Photo
</div>
<div class="editor-field">
<input id="Photo" name="Photo" type="file" />
</div>
<p>
<%: Html.Hidden("DeveloperID")%>
<%: Html.Hidden("CreateDate")%>
<input type="submit" value="Save" />
</p>
</fieldset>
<%} %>
</div>
I got the same issue. here is the solution I found.
Class property:
public byte[] Logo { get; set; }
View Code:
#using (Html.BeginForm("StoreMyCompany", "MyCompany", FormMethod.Post, new { id = "formMyCompany", enctype = "multipart/form-data" }))
{
<div class="form-group">
#Html.LabelFor(model => model.modelMyCompany.Logo, htmlAttributes: new { #class = "control-label col-md-3" })
<div class="col-md-6">
<input type="file" name="Logo" id="fileUpload" accept=".png,.jpg,.jpeg,.gif,.tif" />
</div>
</div>
}
Controller Code:
public ActionResult StoreMyCompany([Bind(Exclude = "Logo")]MyCompanyVM model)
{
try
{
Company objCompany = new Company();
byte[] imageData = null;
if (Request.Files.Count > 0)
{
HttpPostedFileBase objFiles = Request.Files["Logo"];
using (var binaryReader = new BinaryReader(objFiles.InputStream))
{
imageData = binaryReader.ReadBytes(objFiles.ContentLength);
}
}
}
catch (Exception ex)
{
Utility.LogError(ex);
}
return View();
}
}
i just excluded Logo from controller's call.
I have the same error, but the solution above didn't work for me, instead I notice that my Model property name is the same as the parameter name I am passing with the controller:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult EditSOP(File file, HttpPostedFileBase Upload)
My Model property name is
public byte[] Upload { get; set; }
After renaming it on a different parameter name, it now works:
public ActionResult EditSOP(File file, HttpPostedFileBase UploadFile)