FormCollection MVC5 not passing decimal to controller - c#

i keep getting errors when trying to post an <input type="number"> from my view to my controller using FormCollection. the database type for expenseBackup is a decimal(8,2). I keep getting "Cannot impliticity convert string to decimal?". Then when i try expenseBackup = Int32.Parse(formValues["expenseBackup"]), i get "Input string was not in correct format". i don't want to have to convert anything in the controller i don't understand why it won't just pass as a decimal through the FormCollection.
Controller
[HttpPost]
public ActionResult Create(FormCollection formValues)
{
var data = new usr_ebillingClientDatabase()
{
client = formValues["client"], //is a string from form
expenseBackup = formValues["expenseBackup"] //is a decimal from form
};
dataContext.table1.InsertOnSubmit(data);
try
{
dataContext.SubmitChanges();
return RedirectToAction("Index");
}
catch (Exception e)
{
return RedirectToAction("Index");
}
}
View
<div class="form-group">
<div class="col-md-10">
#Html.EditorFor(model => model.expenseBackup, new { htmlAttributes = new { #class = "form-control" , , #type="number", #step=".01" } })
</div>
</div>

when you're reading the field from formValues["expenseBackup"] it's being read as a string. Convert it to a decimal using Convert.ToDecimal().
expenseBackup = Convert.ToDecimal(formValues["expenseBackup"] ?? 0m);

FormCollection is a key-value pair collection (NameValueCollection) which returns values as string based from provided key, which is also a string. If you're in doubt which number format applied by numeric input during submit, use combination of decimal.TryParse() and if-condition with string.IsNullOrEmpty() to check null/empty string value:
decimal expense;
if (!string.IsNullOrEmpty(formValues["expenseBackup"])
&& decimal.TryParse(formValues["expenseBackup"], out expense))
{
var data = new usr_ebillingClientDatabase()
{
client = formValues["client"],
expenseBackup = expense
};
// insert to database
}
else
{
// unable to parse numeric value, do something else
}
If you're sure that numeric representation passed in FormCollection uses certain decimal separator other than default, use NumberFormatInfo when parsing with decimal.Parse()/decimal.TryParse():
var numberFormat = new System.Globalization.NumberFormatInfo() { NumberDecimalSeparator = "," };
var data = new usr_ebillingClientDatabase()
{
client = formValues["client"],
expenseBackup = decimal.Parse(formValues["expenseBackup"], numberFormat);
};
However, I recommend using strongly-typed viewmodel over FormCollection because you're using EditorFor, and it will pass property values directly to controller when viewmodel name is included as action parameter.

Related

Passing list/model as parameter with #url.action

Is there a way to pass list as parameter for #url.action or is there a better solution for this?
Pseudo code:
This doesn't pass anything, unless I define index for my model or list.
#Url.Action("DeleteConfirmed", "Home", new { selectedids = /*model or list?*/ }, null)
I need to pass list or model to this:
public ActionResult DeleteConfirmed(List<int> selectedids) {
//Code
return View("Index");
}
I join them as a string and then convert that back on the server; this means selectedids would need to be a string on the server, which you would string split on comma and convert each value to long.
#Url.Action("DeleteConfirmed", "Home", new { selectedids = String.Join(",", Model.IDS) })

TextBoxFor decimal

In my database I stored fields with the data type decimal. I am using exactly the same (decimal) data type in my ASP.NET application.
This is inside my view in order to display the value.
#Html.TextBoxFor(model => model.Stock, new { id = "Stock", #class = "k-textbox" })
This pretty straight forward. The only issue I am facing is that by default in my view the data is displayed with 4 decimal places.
I give you a few examples on how it looks and how it should look:
1,0000 => 1
1,2000 => 1,2
1,4300 => 1,43
1,8920 => 1,892
1,5426 => 1,5426
As you can see I want to cut off all the 0 as decimal places (only when displayed in the view).
Remember: I am using commas instead of decimal points.
Edit:
My model
public class Article
{
public decimal? Stock{ get; set; }
}
The G29 argument of the string.Format method does exactly what you want.
You can use the the following attribute on your models Stock value.
[DisplayFormat(DataFormatString = "{0:G29}", ApplyFormatInEditMode = true)]
Or you can use the overload which #Chris mentioned.
#Html.TextBoxFor(model => model.Stock, "{0:G29}", new { id = "Stock", #class = "k-textbox" })
You can use {0:G29} like this:
#{
string temp = string.Format("{0:G29}", decimal.Parse(Model.Stock.ToString()));
#Html.TextBoxFor(model => temp)
}
Or with string interpolation:
#{
string temp = $"{decimal.Parse(Model.Stock.ToString()):G29}";
#Html.TextBoxFor(model => temp)
}
EDIT:
The reason that you can't get the value in your Controller after you save it is that the model binder can't find a property with name temp. You can use a TextBox instead of TextBoxFor to solve this issue like this:
string temp = $"{decimal.Parse(Model.Stock.ToString()):G29}";
#Html.TextBox("Stock" , temp)
Or if you still want to use TextBoxFor you can just rename the temp variable to Stock:
string Stock = string.Format("{0:G29}", decimal.Parse(Model.Stock.ToString()));
#Html.TextBoxFor(model => Stock)
There is an overload of TextBoxFor that takes a format parameter that it uses to format the text.
This will allow you to format your number in any way you want.

display a message to user if field is blank

Afternoon Folks,
I am new to c# and im trying to create an if statement to check the value of two fields and if both of these fields are blank, to then display a message to the user.
My two fields are DateofBirth with a datatype of DateTime and Age with a datatype of int. Im using studio 2013 and have a c# mvc project.
In my create.cshtml page i am using razor syntax for these two form fields.
#Html.EditorFor(model => model.client.DateOfBirth, new { htmlAttributes = new { #class = "form-control", #placeholder = "dd-mm-yyyy" } })
and
#Html.EditorFor(model => model.client.AgeNotKnown, new { htmlAttributes = new { #class = "form-control", #placeholder = "Age in Years" } })
the user needs to fill in either one or the other field when submitting the form.
In my controller and my HttpPost for the ActionResult Create. I have tried a couple of ways to get this working via an if statement but i get seem to get this to work.
I have tried using the string.IsNullOrEmpty method, but as these are DateTime and int datatypes this will not work. See sample below.
if (string.IsNullOrEmpty(clientViewRecord.client.AgeNotKnown));
{
MessageBox.Show("please an Age if DOB not known");
}
db.ClientRecords.Add(clientViewRecord.client);
db.SaveChanges();
return RedirectToAction("MainMenu", "Home");
I get three errors here:
Argument 1: cannot convert from 'int?' to 'string'
The name 'MessageBox' does not exist in the current context 3) The
best overloaded method match for 'string.IsNullOrEmpty(string)' has
some invalid arguments
The best overloaded method match for 'string.IsNullOrEmpty(string)' has
some invalid arguments
Another way i have tried to get this working is the following...
if (clientViewRecord.client.AgeNotKnown == 0 || clientViewRecord.client.DateOfBirth == 0);
{
MessageBox.Show("please enter an Age or if DOB");
}
db.ClientRecords.Add(clientViewRecord.client);
db.SaveChanges();
return RedirectToAction("MainMenu", "Home");
I get the same issue for the message box and the following for the DateofBirth filed.
Operator '==' cannot be applied to operands of type 'System.DateTime?' and 'int'
Im new to c# but think that im kinda on the right lines, i think just need a little help or any suggestions.
Regards
Betty
? means nullable whose default value will be null if i use int? its default value will be null if i use int its default value will be 0
about validation you can use ModelState for validation in MVC and add a custom validation
#Html.ValidationMessage("validation")
#Html.EditorFor(model => model.DateOfBirth, new { htmlAttributes = new { #class = "form-control", #placeholder = "dd-mm-yyyy" } })
#Html.EditorFor(model => model.AgeNotKnown, new { htmlAttributes = new { #class = "form-control", #placeholder = "Age in Years" } })
i used #Html.ValidationMessage("validation") which will show the validation message if i return any and in your action
if (cls.DateOfBirth == null && cls.AgeNotKnown == null)
{
ModelState.AddModelError("validation","Please select one");
return View();
}
in action it will check condition if both are null then it will return to the same view including the validation message of key validation which is defined in the view.
First of all MessageBox class is belong to windows forms. If you want to wanr the user you should use validations. I prefer jquery validation
To add control like this, just put a breakpoint to your code and look want data coming from your form. This way you can decide how do you want to control your data.
System.DateTime? and int?, this question marks tell you that these variables can be null. So you should consider that while comparing.
First of all create ViewModel for this kind of validation
public class ClientViewModel
{
[Required, DataType(DataType.Date), DisplayFormat(DataFormatString = "{0:dd-MM-yyyy}", ApplyFormatInEditMode = true)]
public DateTime Date { get; set; }
[Required]
public int Age { get; set; }
}
In View
#model Models.ClientViewModel #*reference to your model usally create in Models folder*#
#Html.ValidationSummary() #* add this for validation summary displays here.*#
#Html.EditorFor(model => model.Date, new { htmlAttributes = new { #class = "form-control", #placeholder = "dd-mm-yyyy" } })
#Html.ValidationMessageFor(m => m.Date)
#Html.EditorFor(model => model.Age, new { htmlAttributes = new { #class = "form-control", #placeholder = "Age in Years" } })
#Html.ValidationMessageFor(m => m.Age)
#* Add jqueryval bundles which is created in app_start/BundleConfig *#
#section Scripts{
#Scripts.Render("~/bundles/jqueryval")
}
In Controller
//Change the name of PostMethod
public ActionResult PostMethod(Models.ClientViewModel model )
{
if (ModelState.IsValid)
{
// do your stuff
}
return View();
}

How to get list of objects which have id from session state and show it in dropdownlist?

I have 2 tables in database
Subject(subjID, subjName, tchID)
Teacher(tchID, tchName)
How to get list of subjects which have tchID value from Sesstion state and show it in dropdownlist?
My controller:
public ActionResult GetListSubj()
{
db = new DatabaseMng();
Teacher tch = db.Teachers.Find(Session["tchID"].ToString());
ViewBag.subjID = new SelectList(db.Subjects, "subjID", "subjName");
return View();
}
In view:
...
#Html.DropDownList("subjID", String.Empty)
This is my code, it's not complete, because it return all subjects, but I want subjects have tchID from Session state in Login View:
[HttpPost]
public ActionResult Login(Teacher model, FormCollection f)
{
db = new DatabaseMng();
string id = f["txtID"];
string pw= f["txtPass"];
if (ModelState.IsValid)
{
Session["tchID"] = id;
return RedirectToAction("GetListSubj", "Teacher");
}
return View();
}
Currently you are creating the SelectList object using db.Subjects which is all the items in the Subject table.
Include a where clause when querying db.Subjects. You can use the value from session for your where clause.
var idFromSession = string.empty;
if (Session["tchID"] != null)
{
idFromSession = Session["tchID"].ToString();
}
var filterdSubjects = db.Subjects.Where(s=>s.tchID == idFromSession);
// Use filterdSubjects to build your dropdown.
Assuming tchID property is of string type. If it is numeric type(Int32/Int64), convert your session value to numeric type and use that in your where clause.
var idFromSession = 0;
if (Session["tchID"] != null)
{
idFromSession = Convert.ToInt32(Session["tchID"]);
}
var filterdSubjects = db.Subjects.Where(s=>s.tchID==idFromSession);
You might also consider to switch to a more robust strongly typed approach which uses view models to transfer data from your action methods to view rather than relying on dynamic stuff like ViewBag/ViewData.

Why ModelState.IsValid always return false in mvc [duplicate]

This question already has an answer here:
ModelState.IsValid is always returning false [duplicate]
(1 answer)
Closed 7 years ago.
In my controller this code:
[HttpPost]
public ActionResult Edit(Company company, FormCollection IsCostCenters)
{
if (ModelState.IsValid)
{
Company objNewCompany = new Company();
//oParty.CostCenters.Clear();
using (PaymentAdviceEntityContainer db1 = new PaymentAdviceEntityContainer())
{
objNewCompany = db1.Companies.Find(company.Id);
objNewCompany.CostCenters.Clear();
string[] temp = IsCostCenters["CostCenters"].Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
foreach (var s in temp)
{
if (s != "false")
{
CostCenter oCostCenter = new CostCenter();
oCostCenter = db1.CostCenters.Find(Convert.ToInt32(s));
objNewCompany.CostCenters.Add(oCostCenter);
}
}
db1.SaveChanges();
}
db.Entry(company).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.CreatedById = new SelectList(db.Employees, "Id", "FirstName", company.CreatedById);
return View(company);
}
And my view code as below
#using PaymentAdviceEntity;
#{
ViewBag.Title = "Edit";
List<CostCenter> clist = new List<CostCenter>();
clist = ((List<CostCenter>)ViewBag.CostCenters).ToList();
}
<div style="line-height: 22px; width: 100%;height :3%; float: left; ">
#{
foreach (var item in clist)
{
<div style="line-height: 22px; width: 28%; float: left;">
<span class="checkbox">#Html.CheckBox("CostCenters", item.IsChecked, new { #value = item.Id })</span>
<span>#Html.DisplayFor(modelItem => item.Name)</span>
</div>
}
}
So please what is reason ModelState.IsValid is return false in page post time ...
Please post your Model Class.
To check the errors in your ModelState use the following code:
var errors = ModelState
.Where(x => x.Value.Errors.Count > 0)
.Select(x => new { x.Key, x.Value.Errors })
.ToArray();
OR: You can also use
var errors = ModelState.Values.SelectMany(v => v.Errors);
Place a break point at the above line and see what are the errors in your ModelState.
As Brad Wilson states in his answer here:
ModelState.IsValid tells you if any model errors have been added to
ModelState.
The default model binder will add some errors for basic type
conversion issues (for example, passing a non-number for something
which is an "int"). You can populate ModelState more fully based on
whatever validation system you're using.
Try using :-
if (!ModelState.IsValid)
{
var errors = ModelState.SelectMany(x => x.Value.Errors.Select(z => z.Exception));
// Breakpoint, Log or examine the list with Exceptions.
}
If it helps catching you the error. Courtesy this and this
"ModelState.IsValid" tells you that the model is consumed by the view (i.e. PaymentAdviceEntity) is satisfy all types of validation or not specified in the model properties by DataAnotation.
In this code the view does not bind any model properties.
So if you put any DataAnotations or validation in model (i.e. PaymentAdviceEntity). then the validations are not satisfy.
say if any properties in model is Name which makes required in model.Then the value of the property remains blank after post.So the model is not valid (i.e. ModelState.IsValid returns false).
You need to remove the model level validations.

Categories