ASP.NET MVC Post Collection CamelCase Serialization - asp.net-mvc-4

XOn an ASP.NET MVC Website I´m posting a List of models, wrapped in a classe's property, by submitting a form.
When the "List propertys" name contains a
capital letter beside the first one, deserialization seems to fail when posting back, hence the List property of the wrapping class received as parameter in the controller method is null. If the propertie`s name doesn't contain any further capital letters all going fine.
For better comprehension I created an example with two wrapping classes Department & DepartmentX:
namespace CollectionPropertyCamelCase.Models
{
public class Employee
{
public string Name { get; set; }
public int Age { get; set; }
}
public class Department
{
public IList<Employee> Employees { get; set; }
}
public class DepartmentX
{
public IList<Employee> EmployeesX { get; set; }
}
}
namespace CollectionPropertyCamelCase.Controllers
{
public class DepartmentController : Controller
{
// ---> Works fine
public ActionResult Index()
{
var d = new Department()
{
Employees = new List<Employee>()
{
new Employee(){ Name = "Paul", Age = 35},
new Employee(){ Name = "Laura", Age = 27},
new Employee(){ Name = "John", Age = 99}
}
};
return View(d);
}
[HttpPost]
public ActionResult Index(Department d)
{
// All fine: Parameter d`s poperty Employees is an instance of
// List<Employee> conatining three instances of Employee
// providing the values as defined in Index().
return View(d);
}
// <--- Works fine
// ---> Doesn't work
public ActionResult IndexX()
{
var d = new DepartmentX()
{
// this is the troublemaker: Usage of 'X' in the propertyname
EmployeesX = new List<Employee>()
{
new Employee(){ Name = "Paul", Age = 35},
new Employee(){ Name = "Laura", Age = 27},
new Employee(){ Name = "John", Age = 99}
}
};
return View(d);
}
[HttpPost]
public ActionResult IndexX(DepartmentX d)
{
// Not so fine: Parameter d`s poperty EmployeesX is null
return View(d);
}
// <--- Doesn't work
}
}
#* Index.cshtml *#
#model CollectionPropertyCamelCase.Models.Department
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
#using (Html.BeginForm())
{
<table>
#for (int i = 0; i < Model.Employees.Count; i ++)
{
<tr>
<td>
#Html.TextBoxFor(modelItem => Model.Employees[i].Name)
</td>
<td>
#Html.TextBoxFor(modelItem => Model.Employees[i].Age)
</td>
</tr>
}
</table>
<input type="submit" />
}
#* IndexX.cshtml *#
#model CollectionPropertyCamelCase.Models.DepartmentX
#{
ViewBag.Title = "IndexX";
}
<h2>IndexX</h2>
#using (Html.BeginForm())
{
<table>
#for (int i = 0; i < Model.EmployeesX.Count; i++)
{
<tr>
<td>
#Html.TextBoxFor(modelItem => Model.EmployeesX[i].Name)
</td>
<td>
#Html.TextBoxFor(modelItem => Model.EmployeesX[i].Age)
</td>
</tr>
}
</table>
<input type="submit" />
}
Does anyone have a clue how to influence deserialization, so camelcased propery names can be used at that place? Thanks in advance!

Related

#Helpers In ASP.NET Core

I want to use Razor helper in .net core
I use this code
#{
void DrawRow(CategoryModel child, int parentNo)
{
#<text>
<tr style="display: none;">
<td><span class="treegrid-indent"></span><span class="treegrid-expander"></span>#child.Name</td>
</td>
</tr>
</text>;
}
}
but when use this , get error
The "#" character must be followed by a ":", "(", or a C# identifier. If you intended to switch to markup, use an HTML start tag,
You can achieve same requirement using a view component in ASP.NET Core application, like below.
ViewComponent class
[ViewComponent(Name = "DrawRow")]
public class DrawRowComponent : ViewComponent
{
public async Task<IViewComponentResult> InvokeAsync(DrawRowModel model)
{
return View(model);
}
}
ViewComponent Razor view
#model DrawRowModel
#*display: none;*#
<tr style="">
<td>
<span class="treegrid-indent"></span>
<span class="treegrid-expander"></span>
#Model.child.Name
</td>
</tr>
Model Class(es)
public class CategoryModel
{
public string Name { get; set; }
}
public class DrawRowModel
{
public CategoryModel child { get; set; }
public int parentNo { get; set; }
}
Invoke view component in Test View page
#{
ViewData["Title"] = "Test";
var model = new DrawRowModel { child = new CategoryModel { Name = "Category" }, parentNo = 0 };
}
<h1>Test</h1>
#for (int i = 1; i < 6; i++)
{
model.child.Name = "Category" + i.ToString();
model.parentNo = i;
<table>
#await Component.InvokeAsync("DrawRow", model)
</table>
}
Test Result

Data column into db MVC4

<table>
#foreach (DataRow row in Model.Rows)
{
<tr>
#foreach (DataColumn col in Model.Columns)
{
<td>#row[col.ColumnName]</td>
}
</tr>
}
</table>
#Html.ActionLink("Pass", "Insert", "Home")
When clicking the pass link i would like the columns to be inserted into db. Is there any tutorial on how to do this?
Please try this sample.
Create a view model class as follows
public class DataRows
{
public int Column1{ get; set; }
public string Column2 { get; set; }
public double Column3 { get; set; }
}
public class MyModel
{
public virtual DataRows[] DataSet { get; set; }
}
Retrieve all the data using your business logic into MyModel in your controller. I am demonstrating this using a sample code
public TestModel GenerateModel()
{
var model = new TestModel();
model.DataSet = this.GenerateDataGridData().ToArray();
return model;
}
private ICollection<SampleDataSet> GenerateDataGridData()
{
var list = new List<SampleDataSet>()
{
new SampleDataSet() { Column1= 1, Column2= "XXX", Column3= 23 },
new SampleDataSet() { Column1= 2, Column2= "YYY", Column3= 27 },
new SampleDataSet() { Column1= 3, Column2= "ZZ", Column3= 25 }
};
return list;
}
In the Action of your view you will be calling GenerateModel method as follows
public ActionResult MyView()
{
var model = this.GenerateModel();
return this.View(model);
}
Now you restructure your MyView page as follows
#model MyModel
#{
int i = 0;
}
#using (Html.BeginForm("Insert", "Home", FormMethod.Post))
{
<table>
<thead>
<tr>
<th>Column1</th>
<th>Column2</th>
<th>Column3</th>
</tr>
</thead>
<tbody>
#foreach (var row in Model.DataSet)
{
<tr>
<th>#row.Column1<span>#Html.HiddenFor(x => Model.DataSet[i].Column1)</span></th>
<th>#row.Column2<span>#Html.HiddenFor(x => Model.DataSet[i].Column2)</span></th>
<th>#row.Column3<span>#Html.HiddenFor(x => Model.DataSet[i].Column3)</span></th>
</tr>
i++;
}
</tbody>
</table>
<input type="submit" value="Pass" />
}
Now on submiting the data in the view will be posted to your Insert Action of Home controller and you can insert into your DB using your logic
I hope this will be a solution for your query.

Why they are using linq Expression here #Html.RadioButtonFor(m => m.SelectedDepartment, department.Id) #department.Name?

I wanted to know why they are using linq Expression in this
statement:
#Html.RadioButtonFor(m => m.SelectedDepartment, department.Id) #department.Name.How the value of property (Selected Department of company class)
is set when get event of Index controller is called and how the value of
SelectedDepartment (property of company class) is retrieved.
Code:
//This a model class
public class Company
{
public string SelectedDepartment { get; set; } //Property
public List<Department> Departments //Property
{
get
{
SampleDBContext db = new SampleDBContext();
return db.Departments.ToList();
}
}
}
// This is a controller class
class HomeController
{
[HttpGet]
public ActionResult Index() //Controller Method1
{
Company company = new Company();
return View(company);
}
[HttpPost]
public string Index(Company company) //Controller Method2
{
if (string.IsNullOrEmpty(company.SelectedDepartment))
{
return "You did not select any department";
}
else
{
return "You selected department with ID = " + company.SelectedDepartment;
}
}
}
// This is a view
#model MVCDemo.Models.Company
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
#using (Html.BeginForm())
{
foreach (var department in Model.Departments)
{
#Html.RadioButtonFor(m => m.SelectedDepartment, department.Id) #department.Name
}
<br />
<br />
<input type="submit" value="Submit" />
}

System.Collections.Generic.List MVC Error

I want to view the table in Edit.cshtml
I was using the Html.Action to get the table from SurveyQuestionController but it shows the error as below:
The model item passed into the dictionary is of type 'System.Collections.Generic.List``1[System.String]', but this dictionary requires a model item of type 'System.Collections.Generic.IEnumerable`1[SurveyTool.Models.SurveyQuestionModel]'.
Anything that i'm wrong??
Edit.cshtml:
#model SurveyTool.Models.SurveyModel
<div>
<h2>Link</h2>
#Html.Action("QuestionLink", "SurveyQuestion", new { id = Model.SurveyID })
</div>
SurveyQuestionController.cs:
public ActionResult QuestionLink(string SurveyID)
{
var query = (from r in db.SurveyQuestionModels
where r.SurveyId == SurveyID
select r.QuestionLink).Distinct();
return PartialView(query.ToList());
}
QuestionLink.cshtml :
#model IEnumerable<SurveyTool.Models.SurveyQuestionModel>
<br />
<table class="strip">
#foreach (var item in Model)
{
<tr>
<td>#Html.DisplayFor(modelitem => item.QuestionLink)</td>
</tr>
}
</table>
SurveyQuestionModel.cs :
namespace SurveyTool.Models
{
public class SurveyQuestionModel
{
public int Id { get; set; }
public string QuestionLink { get; set; }
}
}
You query is selecting only the QuestionLink property of SurveyQuestionModel (by you use select r.QuestionLink) which is typeof string, hence your returning List<string> to the view, when the view expects List<SurveyQuestionModel>
Change the query to return a collection of SurveyQuestionModel
public ActionResult QuestionLink(string SurveyID)
{
var query = (from r in db.SurveyQuestionModels
where r.SurveyId == SurveyID
select r);
return PartialView(query.ToList());
}
or change the view so the model is List<string>
#model List<string>
#foreach (var item in Model)
{
#Html.DisplayFor(modelitem => item)
}

how to bind data to checkbox from viewmodel

I'm trying to make a view model to show a list of checkboxes. A checkbox will be checked when its ID is found in the database. However, my code is generating an error.
CheckFacilityVN
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace XNet.WebUI.Hotel.ViewModel
{
public class CheckFacilityVM
{
public int FacilityID { get; set; }
public string facilityName { get; set; }
public List<FacilityAvailable> facilityAvailable { get; set; }
}
public class FacilityAvailable
{
public bool isCheck { get; set; }
}
}
My controller
public ActionResult Facility()
{
var htl = _hotelService.ShowRoomFacility(2);
var list = new List<FacilityAvailable>();
foreach (var x in htl)
{
list.Add(new FacilityAvailable { FacilityID = htl.FacilityID, facilityName = htl.FacilityName, isCheck = htl.IsActive });
}
return View();
}
My constructor
public Facility ShowRoomFacility(int HotelID)
{
var x = (from d in db.Facilities
where d.FacilityID == HotelID
select d).FirstOrDefault();
return x;
}
How can I make these checkboxes?
Start by adapting your view model:
public class CheckFacilityVM
{
public int FacilityID { get; set; }
public string FacilityName { get; set; }
public bool IsFacilityAvailable { get; set; }
}
and then use this view model:
public ActionResult Facility()
{
var model = _hotelService
.ShowRoomFacility(2)
.Select(htl => new CheckFacilityVM
{
FacilityID = html.FacilityID,
FacilityName = html.FacilityName,
IsFacilityAvailable = htl.IsActive,
})
.ToList();
return View(model);
}
and then write a corresponding view:
#model List<CheckFacilityVM>
#using (Html.BeginForm())
{
<table>
<thead>
<tr>
<th>Id</th>
<th>Name</th>
<th>Is available</th>
</tr>
</thead>
<tbody>
#for (var i = 0; i < Model.Count; i++)
{
<tr>
<td>
#Html.DisplayFor(x => x[i].FacilityID)
#Html.HiddenFor(x => x[i].FacilityID)
</td>
<td>
#Html.DisplayFor(x => x[i].FacilityName)
#Html.HiddenFor(x => x[i].FacilityName)
</td>
<td>
#Html.CheckBoxFor(x => x[i].IsFacilityAvailable)
</td>
</tr>
}
</tbody>
</table>
<button type="submit">Save</button>
}
and finally:
[HttpPost]
public ActionResult Facility(List<CheckFacilityVM> model)
{
// process the values from the view model here ...
}