Data Table transfer to Model then to the view - mysql

Ok so after alot of research i have concluded that passing a data table to a view is a bad idea ,so how do i pass my data table to a Model and then be able to access each row and column in the view?Sorry i am new to MVC
I start with a simple SQL statement
StringBuilder sbSQL = new StringBuilder();
//// define a list of CustomerModel objects
DataSet tempDS = new DataSet();
//string xSQL = "SELECT PropertyAddress,PropertyTypeDesc,PropertyID FROM KDOR_vwPropertyGeneral ORDER BY PropertyAddress";
System.Data.SqlClient.SqlDataAdapter DbCmd = new System.Data.SqlClient.SqlDataAdapter();
string sqlWhereCont = " WHERE ";
sbSQL.Append("SELECT ");
sbSQL.Append("PropertyAddress As PropertyAddress,");
sbSQL.Append("PropertyTypeDesc As PropertyTypeDesc,");
sbSQL.Append("PropertyID as PropertyID");
sbSQL.Append(" FROM [KDOR_vwPropertyGeneral] ");
if (!string.IsNullOrEmpty(user.Address))
{
sbSQL.Append(sqlWhereCont + "(PropertyAddress) LIKE '" + user.Address + "%'");
sqlWhereCont = "AND ";
}
sbSQL.Append(" ORDER BY ");
sbSQL.Append(" PropertyAddress ");
string MyConnectionString = ConfigurationManager.ConnectionStrings["WLConnection"].ConnectionString;
System.Data.SqlClient.SqlConnection cnn = new System.Data.SqlClient.SqlConnection(MyConnectionString);
System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand(sbSQL.ToString(), cnn);
cmd.CommandTimeout = 30000;
DbCmd.SelectCommand = cmd;
move the data to a DataSet and Data Table
DbCmd.Fill(tempDS, "ResultSet");
DataTable resultSet = tempDS.Tables["ResultSet"];
Add items to Model
var vm = new List<BedroomModel>();
foreach (DataRow dr in tempDS.Tables[0].Rows)
{
vm.Add(new BedroomModel {PropertyAdd = dr.ItemArray[0].ToString() });
vm.Add(new BedroomModel { PropertyDesc = dr.ItemArray[1].ToString() });
vm.Add(new BedroomModel { PropertyID = dr.ItemArray[2].ToString() });
}
Now how to i Access each Item and loop through them in a view? Cause i get an error here is a look at my view
#model DataBaseTest.Models.BedroomModel
#{
ViewBag.Title = "Result";
}
<h2>Result</h2>
#{
ViewBag.Title = "Result";
}
<table border ="1">
<thead>
#* <tr>
#foreach (var col in Model.Columns) {
<th>
#col.ColumnName
</th>
}
</tr>*#
<tr>
<th>Property Address</th>
<th>Property Description</th>
<th>Property ID</th>
</tr>
</thead>
<tbody>
#foreach (var item in Model.PropertyAdd)
{
<tr>
<td>#Model.PropertyAdd</td>
</tr>
}
</tbody>
Model
namespace DataBaseTest.Models
{
public class BedroomModel
{
public string Address { get; set; }
public string PropertyAdd { get; set; }
public string PropertyID { get; set; }
public string PropertyDesc { get; set; }
public IEnumerable<BedroomModel> BedroomModels { get; set; }
}
}
Again Sorry i am new to MVC
Any advice Would be Greatly Appreciated.

You are telling your view that it should look for a single BedroomModel object, when you actually want to pass it a List<BedroomModel> object.
#model List<DataBaseTest.Models.BedroomModel>
As a result, your Model property will be the list itself, so your foreach loop only needs to loop through the Model, not Model.BedroomModels.
#foreach (var item in Model)
{
<tr>
<td>#item.PropertyAdd</td>
<td>#item.PropertyDesc</td>
<td>#item.PropertyID</td>
</tr>
}
Because of this change, you can remove the BedroomModels property from your BedroomModel class.
public class BedroomModel
{
public string Address { get; set; }
public string PropertyAdd { get; set; }
public string PropertyID { get; set; }
public string PropertyDesc { get; set; }
}
That would fix your problem, but I also noticed that when populating your vm list, you are adding three items into the List, where you should only be adding one BedroomModel object. Your foreach loop should look like this:
var vm = new List<BedroomModel>();
foreach (DataRow dr in tempDS.Tables[0].Rows)
{
vm.Add(new BedroomModel
{
PropertyAdd = dr.ItemArray[0].ToString(),
PropertyDesc = dr.ItemArray[1].ToString(),
PropertyID = dr.ItemArray[2].ToString()
};
}
You must also make sure that you are sending the ViewModel into the View. Your Action should return:
return View(vm);

Add this to your view at the top.
#model DataBaseTest.Models.BedroomModel
This will make the view a strongly typed view. Meaning that it knows what model it will be using to display the data and what properties are available.
Then assign your collection in your controller method prior to your view rendering.
I edited this portion. I just now noticed that you were adding a new object for each property instead of assigning the properties to one object and then adding them. Then you will get a null reference.
public ActionResult MyView()
{
BedroomModel lModel = new BedroomModel();
lModel.BedroomModels = new List<BedroomModels>();
DataSet tempDS = CallToBLLOrDAL(); //Do what you need to do to get your data.
//Assign your values to the ViewModel (Aka lModel in this instance).
foreach (DataRow dr in tempDS.Tables[0].Rows)
{
//I am unsure exactly why you are calling ItemArray and adding a new Model for each column.
//Your way.
lModel.BedroomModels.Add(new BedroomModel { PropertyAdd = dr.ItemArray[0].ToString() });
lModel.BedroomModels.Add(new BedroomModel { PropertyDesc = dr.ItemArray[1].ToString() });
lModel.BedroomModels.Add(new BedroomModel { PropertyID = dr.ItemArray[2].ToString() });
//Try this
lModel.BedroomModels.Add(new BedroomModel { PropertyAdd = dr.ItemArray[0].ToString(), PropertyDesc = dr.ItemArray[1].ToString(), PropertyID = dr.ItemArray[2].ToString()});
}
return View(lModel);
}
Then in your view.
#foreach (BedroomModel lBedroomModel in Model.BedroomModels)
{
<td>
#lBedroomModel.PropertyAdd
</td>
}
Debugging tips.
You can set a break point in your view inside of your foreach. Drag your Model down to your watches. You should be able to see the population of your model and all of the values within the current scope.
I am unsure why the coloring is off on the view code snippet.
Let me know what you think.
Please set as answer if this helps.

Related

MVC5 not passing JSON property names through to view

I'm just starting out with MVC, JSON, AJAX, etc and as a side project have been trying to create a data viz dashboard.
Today I followed this guide on how to pass a simple table of data from SQL as JSON to my view: http://techfunda.com/howto/292/list-records-using-json
It mostly worked: the JsonResult comes through from my controller and contains the values but not the property names.
This causes a problem because I'm referencing the property names when I process the data for display in JavaScript.
Here's the SQL data:
Here's my Model:
public partial class vw_Dash_ChartData : IEnumerable<object>
{
[Key]
[JsonProperty(PropertyName = "Classification")]
public string Classification { get; set; }
[JsonProperty(PropertyName = "Count")]
public int Count { get; set; }
public IEnumerator<object> GetEnumerator()
{
yield return Classification;
yield return Count;
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
}
(You'll notice I tried to manually set the [JsonProperty(...)] stuff...it didn't help.)
And here's my JsonResult:
public JsonResult ChartDataJson()
{
var data = new List<vw_Dash_ChartData>();
data = db.vw_Dash_ChartDatas.ToList();
var jsonData = Json(data, JsonRequestBehavior.AllowGet);
return jsonData;
}
(Initially I was sending the data straight through from my DbContext but then thought perhaps it would help to use my vw_Dash_ChartData model. It didn't make a difference).
My view looks like the following:
#{
ViewBag.Title = "Charts";
AjaxOptions options = new AjaxOptions
{
//Confirm = "Are you sure?",
LoadingElementId = "divLoading",
OnSuccess = "processDataMethod",
Url = Url.Action("ChartDataJson")
};
}
<script type="text/javascript">
function processDataMethod(data) {
var output = $("#dataZone");
output.empty();
for (var i = 0; i < data.length; i++) {
var chartData = data[i];
output.append("<tr><td>" + chartData.Classification + "</td><td>" + chartData.Count + "</td></tr>");
}
}
</script>
<div>
<table>
<thead>
<tr>
<th>Classification</th>
<th>Count</th>
</tr>
</thead>
<tbody id="dataZone">
</tbody>
</table>
</div>
#using (Ajax.BeginForm(options))
{
<div id="divLoading" style="color: red; font-size: larger;">
Loading...
</div>
<div>
<button type="submit" id="btnClicky" >Clicky</button>
</div>
}
<script>
$("#btnClicky").trigger("click");
</script>
When I load the page, this is what I get:
and this is the JSON object shown in the browser developer tools;
Any tips/ideas gratefully received! Also, if I'm doing anything stupid do let me know as I'd like to learn best practice for this stuff.
How about?
var jsonData = Json(data.Select(x=> new {
Classification = x.Classification,
Count = x.Count
})
);
return jsonData;

How does Asp.net Core renders a view

How does MVC 6 renders a view. What's the actual method in Razor ViewEngine that generates the html output? Also if possible please explain the process of rendering a view.
May be you could point me to a file on mvc source on github. thanks!
Here is a complete solution of what you are looking for. I used dependency injection to get the HtmlHelper in the controller. You can inject your own helper if you want too.
using Microsoft.AspNet.Html.Abstractions;
using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Mvc.ModelBinding;
using Microsoft.AspNet.Mvc.Rendering;
using Microsoft.AspNet.Mvc.ViewEngines;
using Microsoft.AspNet.Mvc.ViewFeatures;
using Microsoft.AspNet.Mvc.ViewFeatures.Internal;
using Microsoft.Extensions.WebEncoders;
using System.ComponentModel.DataAnnotations;
using System;
public class MyController : Controller
{
private readonly IHtmlGenerator htmlGenerator;
ICompositeViewEngine viewEngine;
IModelMetadataProvider metadataProvider;
private readonly IHtmlHelper helper;
IHtmlEncoder htmlEncoder;
IUrlEncoder urlEncoder;
IJavaScriptStringEncoder javaScriptStringEncoder;
public MyController(IHtmlHelper helper, IHtmlGenerator htmlGenerator, ICompositeViewEngine viewEngine, IModelMetadataProvider metadataProvider, IHtmlEncoder htmlEncoder, IUrlEncoder urlEncoder, IJavaScriptStringEncoder javaScriptStringEncoder)
{
this.htmlGenerator = htmlGenerator;
this.viewEngine = viewEngine;
this.metadataProvider = metadataProvider;
this.htmlEncoder = htmlEncoder;
this.urlEncoder = urlEncoder;
this.javaScriptStringEncoder = javaScriptStringEncoder;
this.helper = helper;
}
[HttpGet]
public IActionResult MyHtmlGenerator()
{
MyViewModel temp = new MyViewModel();
var options = new HtmlHelperOptions();
options.ClientValidationEnabled = true;
ViewDataDictionary<MyViewModel> dic = new ViewDataDictionary<MyViewModel>(this.metadataProvider, new ModelStateDictionary());
ViewContext cc = new ViewContext(ActionContext, new FakeView(), dic, TempData, TextWriter.Null, options);
var type = typeof(MyViewModel);
var metadata = this.metadataProvider.GetMetadataForType(type);
ModelExplorer modelEx = new ModelExplorer(this.metadataProvider, metadata, temp);
ViewData["Description"] = "test desc";
ViewData["Id"] = 1;
this.ViewData = new ViewDataDictionary(this.metadataProvider, new ModelStateDictionary());
IHtmlHelper<MyViewModel> dd = new HtmlHelper<MyViewModel>(this.htmlGenerator, this.viewEngine, this.metadataProvider, this.htmlEncoder, this.urlEncoder, this.javaScriptStringEncoder);
((ICanHasViewContext)dd).Contextualize(cc);
dd.ViewContext.ViewData = this.ViewData;
var desc = GetString(dd.TextBoxFor(m => m.ID));
var ID = GetString(dd.TextBoxFor(m => m.Description));
// Do whatever you want with the ID and desc
return new ContentResult() { Content = ID + desc };
}
public static string GetString(IHtmlContent content)
{
var writer = new System.IO.StringWriter();
content.WriteTo(writer, new HtmlEncoder());
return writer.ToString();
}
}
public class MyViewModel : BaseAssetViewModel
{
// [RegularExpression(#"^-?\d{1,13}(\.\d{0,5})?$|^-?\.\d{1,5}$")]
[Required]
public int ID { get; set; }
[MinLength(2)]
public string Description { get; set; }
// Property with no validation
public string Other { get; set; }
}
public class FakeView : IView
{
string IView.Path
{
get
{
throw new NotImplementedException();
}
}
public Task RenderAsync(ViewContext viewContext)
{
throw new InvalidOperationException();
}
Task IView.RenderAsync(ViewContext context)
{
throw new NotImplementedException();
}
}
I don't know if this may be of help, may be you have to start to look at tag helpers:
https://github.com/DamianEdwards/TagHelperStarterWeb
they're working to a different way to create helpers that integrate in the page in a more natural way.

Html.ListBoxFor Object reference not set to an instance of an object Error

I am using view model to display a dropdownlist and i am also trying to get the value of the selected list, here is my view model
public class CreateJobViewModel
{
public int[] SelectedIndustriesIds { get; set; }
public IList<SelectListItem> IndustriesList { get; set; }
}
My controller
public ActionResult Create()
{
var industryList = repository.GetAllIndustries();
var model = new CreateJobViewModel
{
IndustriesList = industryList.Select(i => new SelectListItem
{
Value = i.IndustryId.ToString(),
Text = i.Name
}).ToList()
};
return View("~/Views/Dashboard/Job/Create.cshtml", model);
}
My post controller
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(CreateJobViewModel model)
{
try
{
var job = new Job()
{
Title = "hi",
EmploymentHourId = 1,
LocationId = 1,
Salary = 50,
SalaryPeriodId = 1,
PostCode = 2131,
Role = "world",
Description = "hello",
IsPublished = false,
ShiftId = 1,
WorkDayId = 1,
NumberOfPosition = 5,
Meal = false,
SecondYearVisa = true,
Sponsorship = true,
Accommodation = true,
DurationId = 1,
IndustryExperiencePeriod = 5,
Id = User.Identity.GetUserId(),
};
foreach (int id in model.SelectedIndustriesIds)
{
var industry = repository.Industry(id);
job.Industries.Add(industry);
}
foreach (int id in model.SelectedSpecialRequirementsId)
{
var special = repository.SpecialRequirement(id);
job.SpecialRequirements.Add(special);
}
repository.AddJob(job);
return RedirectToAction("Create");
}
catch
{
return View("~/Views/Dashboard/Job/Create.cshtml");
}
}
Every time i try to submit the selected value, i get Object reference not set to an instance of an object Error on the following line in my view:
#model Taw.WebUI.Models.CreateJobViewModel
#Html.ListBoxFor(m => m.SelectedIndustriesIds, Model.IndustriesList) -- here i get the error
Any reason why?
When you submit the form your throwing an exception (confirmed in the comments) and in the catch block you are returning the view, which throws the exception you are seeing because Model.IndustriesList is null. You need to re-assign the value before you return the view.
Since you need to assign SelectLists in the GET method and in the POST method if you return the view, I tend to re-factor this to a separate method to keep the controller code a bit cleaner. Note the following code is based on your model property being public SelectList IndustriesList { get; set; } which is a bit simpler than building IList<SelectListItem>
private void ConfigureViewModel(CreateJobViewModel model)
{
var industryList = repository.GetAllIndustries();
model.IndustriesList = new SelectList(industryList, "IndustryId", "Name")
// any other common stuff
}
and then in the action methods
public ActionResult Create()
{
var model = new CreateJobViewModel();
ConfigureViewModel(model);
return View(model);
}
public ActionResult Create(CreateJobViewModel model)
{
try
{
....
}
catch
{
ConfigureViewModel(model);
return View(model);
}
}
Note its also good practice to test if the model is valid before attempting to save it
public ActionResult Create(CreateJobViewModel model)
{
if (!ModelState.IsValid)
{
ConfigureViewModel(model);
return View(model); // return the view so the user can correct validation errors
}
....

'foreach' to perform an action for all the rows in a table

I have following class & DataContext Structure,
public class Accounts
{
public string AccountName { get; set; }
public string SecretKey { get; set; }
}
class MyDataContext : DataContext
{
public MyDataContext (string ConnectionString) : base(ConnectionString)
{
}
public Table<Accounts> AllAccounts
{
get
{
return this.GetTable<Accounts>();
}
}
}
I want to get all the accounts from 'Accounts Table' and use each of their SecretKeys to get PIN and show all those accounts in list box...
Problem is I cant create foreach statement
something like
foreach (AllAccountsAC in MyDataContext.Accounts)
First, you can't do a foreach loop without typing the variable. For a Table, you would have to do the foreach on its rows:
Table t = new Table();
foreach (TableRow tr in t.Rows)
{
//enter code here
}
Once you have the row you can get the data.
Second, you can't type a Table. You could use a typed List (such as List<Accounts> for your class) and do the same thing, but use the type set in the List:
List<Accounts> AccountList = new List<Accounts>();
foreach (Accounts a in AccountList)
{
//enter code here
}
Once you have the object from the list, you can perform any functions on it that you need.

Json.net deseralize to a list of objects in c# .net 2.0

I'm trying to deseralize some json into a collection (list), but I'm not sure which method will return a list of objects, or do I have to loop through something and copy it to my own list?
Can anyone tell me the syntax or method I should use for this.
I've created my object with some properties, so it's ready to be used to hold the data. (title,url,description)
I've tried this, but it doesn't seem quite right
List<newsItem> test = (List<newsItem>)JsonConvert.DeserializeObject(Fulltext);
Did you try looking at the help?
http://james.newtonking.com/json/help/?topic=html/SerializingCollections.htm
string json = #"[
{
""Name"": ""Product 1"",
""ExpiryDate"": ""\/Date(978048000000)\/"",
""Price"": 99.95,
""Sizes"": null
},
{
""Name"": ""Product 2"",
""ExpiryDate"": ""\/Date(1248998400000)\/"",
""Price"": 12.50,
""Sizes"": null
}
]";
List<Product> products = JsonConvert.DeserializeObject<List<Product>>(json);
Console.WriteLine(products.Count);
// 2
Product p1 = products[0];
Console.WriteLine(p1.Name);
// Product 1
I'm using those extension methods:
public static string ToJSONArray<T>(this IEnumerable<T> list)
{
DataContractJsonSerializer s = new DataContractJsonSerializer(typeof(IEnumerable<T>));
MemoryStream ms = new MemoryStream();
s.WriteObject(ms, list);
return GetEncoder().GetString(ms.ToArray());
}
public static IEnumerable<T> FromJSONArray<T>(this string jsonArray)
{
if (string.IsNullOrEmpty(jsonArray)) return new List<T>();
DataContractJsonSerializer s = new DataContractJsonSerializer(typeof(IEnumerable<T>));
MemoryStream ms = new MemoryStream(GetEncoder().GetBytes(jsonArray));
var result = (IEnumerable<T>)s.ReadObject(ms);
if (result == null)
{
return new List<T>();
}
else
{
return result;
}
}
You need to decorate your Objects like this one:
[DataContract]
public class MyJSONObject
{
[DataMember]
public int IntValue { get; set; }
[DataMember]
public string StringValue { get; set; }
}
try using array instead of generic list. this may help.