I use a standard set of classes for binding server side DataTables.net grids to data sources.
public class DataTable
{
// Grid properties
public int draw { get; set; }
public List<DataTableColumn> columns { get; set; }
public List<DataTableOrder> order { get; set; }
public int start { get; set; }
public int length { get; set; }
public DataTableColumnSearch search { get; set; }
}
public class DataTableColumn
{
public string data { get; set; }
public string name { get; set; }
public bool searchable { get; set; }
public bool orderable { get; set; }
public DataTableColumnSearch search { get; set; }
}
public class DataTableColumnSearch
{
public string value { get; set; }
public bool regex { get; set; }
}
public class DataTableOrder
{
public int column { get; set; }
public string dir { get; set; }
}
public class Grid
{
public int start { get; set; }
public int recordsFiltered { get; set; }
public int recordsTotal { get; set; }
public object data { get; set; }
public void Setup<T>(IQueryable<T> r, DataTable p)
{
// Filter, sort and bind the data data to this.data
}
}
Then, in MVC 5 I was able to use the QueryString model binding:
public async Task<JsonResult> GetDataTable(DataTable p)
Everything was bound, and the column, search and order objects were all set.
I'm setting up a new project in .NET Core and this now only works if you accept [HttpPost] and post the DataTables.net request to the controller.
If I use the [HttpGet] method, then the DataTable object binds correctly, but no child items (DataTableColumn, DataTableSearch or DataTableOrder) bind.
The Form Data and QueryString data are the same:
draw:1
columns[0][data]:Col1
columns[0][name]:
columns[0][searchable]:true
columns[0][orderable]:true
columns[0][search][value]:
columns[0][search][regex]:false
columns[1][data]:Col2
columns[1][name]:
columns[1][searchable]:true
columns[1][orderable]:true
columns[1][search][value]:
columns[1][search][regex]:false
order[0][column]:0
order[0][dir]:asc
start:0
length:10
search[value]:v6
search[regex]:false
I'd prefer to use a GET request, as it is getting data, so shouldn't need to post. As said, this was working in MVC 5, so I'm not sure what has changed?
EDIT TO ADD
As per the comments, it's just using the standard model binder:
public class OutboundCaims: Controller
{
//[HttpGet]
[HttpPost]
[Route("Claims")]
public async Task<JsonResult> GetClaims(DataTable p) { }
}
If using POST, the DataTable class is bound correctly by the model binder, using GET it isn't. Both POST and GET produce the same output as above when viewed in Chrome dev tools, so pretty sure it's not that.
The request is made using the standard set of jQuery ajax requests built into DataTables.net.
Edit to add: REQUEST URL using a GET method:
http://localhost:55319/api/DataTable?draw=1&columns%5B0%5D%5Bdata%5D=col1&columns%5B0%5D%5Bname%5D=&columns%5B0%5D%5Bsearchable%5D=true&columns%5B0%5D%5Borderable%5D=true&columns%5B0%5D%5Bsearch%5D%5Bvalue%5D=&columns%5B0%5D%5Bsearch%5D%5Bregex%5D=false&columns%5B1%5D%5Bdata%5D=col2&columns%5B1%5D%5Bname%5D=&columns%5B1%5D%5Bsearchable%5D=true&columns%5B1%5D%5Borderable%5D=true&columns%5B1%5D%5Bsearch%5D%5Bvalue%5D=&columns%5B1%5D%5Bsearch%5D%5Bregex%5D=false&columns%5B2%5D%5Bdata%5D=contract&columns%5B2%5D%5Bname%5D=&columns%5B2%5D%5Bsearchable%5D=true&columns%5B2%5D%5Borderable%5D=true&columns%5B2%5D%5Bsearch%5D%5Bvalue%5D=&columns%5B2%5D%5Bsearch%5D%5Bregex%5D=false&columns%5B3%5D%5Bdata%5D=manufacturer&columns%5B3%5D%5Bname%5D=&columns%5B3%5D%5Bsearchable%5D=true&columns%5B3%5D%5Borderable%5D=true&columns%5B3%5D%5Bsearch%5D%5Bvalue%5D=&columns%5B3%5D%5Bsearch%5D%5Bregex%5D=false&columns%5B4%5D%5Bdata%5D=owner&columns%5B4%5D%5Bname%5D=&columns%5B4%5D%5Bsearchable%5D=true&columns%5B4%5D%5Borderable%5D=true&columns%5B4%5D%5Bsearch%5D%5Bvalue%5D=&columns%5B4%5D%5Bsearch%5D%5Bregex%5D=false&order%5B0%5D%5Bcolumn%5D=0&order%5B0%5D%5Bdir%5D=asc&start=0&length=10&search%5Bvalue%5D=&search%5Bregex%5D=false&_=1478804216098
This maps to the same as the POST request, just the model binder doesn't work.
Related
I’m new to MVC so I’m not sure if this is the correct way of doing this. What I’m trying to do is send some JSON data to my controller via ajax, then to my model, to eventually do something to it.
The object I’m sending looks like this before I JSON it on the javascript side
bannerID:undefined
bannerMode:"WIDGET"
heightSettings:"0"
images:Array[2]
toggleArrows:"true"
toggleIndicators:"true"
transitionSpeed:""
widthSettings:"0"
When I JSON it looks like this, when I view it on my controller by replacing widget with string i get this.
{"bannerMode":"WIDGET","transitionSpeed":"","toggleArrows":"true","toggleIndicators":"true","widthSettings":"0","heightSettings":"0","images":
[{"id":0,"orderRank":"1","imageLink":"http://localhost:49999/img/admin/banner/example.jpg"},{"id":1,"orderRank":"2"}]}
In the parameters of the controller of my controller I have a widget model.
public ActionResult Index(widget widgetData){
return View("~/Views/widgets/_dynamicWidget.cshtml", widgetData);
}
My widget model looks like this.
public class widget
{
public string bannerMode { get; set; }
public int transitionSpeed { get; set; }
public bool toggleArrows { get; set; }
public bool toggleIndicators { get; set; }
public int widthSettings = 20;
private string lang;
private List<WidgetList> images1;
public widget(string lang, List<WidgetList> images1)
{
this.lang = lang;
this.images1 = images1;
}
public int heightSettings{ get; set; }
public List<ImageList> images { get; set; }
}
public class ImageList
{
public int id { get; set; }
public int orderRank { get; set; }
public string imageLink { get; set; }
}
I’m guessing the data should be set into the model ?
But in my view I’m getting a null error when I try to show this data.
Your widget class does not have a public parameterless constructor, so I'm guessing the model binder is failing there.
I'm trying to create an object that represents the values that datatables supplies to my web api call, which I'll then route to another api that actually returns the values (to separate the datatables nonsense from the api interface).
After researching a bit on the datatables wiki I ended up with the following objects defined:
public class DataTableParameters
{
public int draw { get; set; }
public int start { get; set; }
public int length { get; set; }
public order[] order { get; set; }
public column[] columns { get; set; }
}
public class order
{
public int column { get; set; }
public string dir { get; set; }
}
public class column
{
public string data { get; set; }
public string name { get; set; }
public bool searchable { get; set; }
public bool orderable { get; set; }
public search search { get; set; }
}
public class search
{
public string value { get; set; }
public bool regex { get; set; }
}
However, when I try to use them as arguments to the DataTables api controller, it comes out null:
public DataTableResult Get(DataTableParameters parameters) //parameters is null!
{
return new DataTableResult();
}
As far as I understood it, model binding should be reading the result and applying it to my object. This is an example call to the api from the front end:
Key Value
Request GET /MVC/api/DataTables?action=Get&draw=1&columns%5B0%5D%5Bdata%5D=0&columns%5B0%5D%5Bname%5D=&columns%5B0%5D%5Bsearchable%5D=true&columns%5B0%5D%5Borderable%5D=true&columns%5B0%5D%5Bsearch%5D%5Bvalue%5D=&columns%5B0%5D%5Bsearch%5D%5Bregex%5D=false&columns%5B1%5D%5Bdata%5D=1&columns%5B1%5D%5Bname%5D=&columns%5B1%5D%5Bsearchable%5D=true&columns%5B1%5D%5Borderable%5D=true&columns%5B1%5D%5Bsearch%5D%5Bvalue%5D=&columns%5B1%5D%5Bsearch%5D%5Bregex%5D=false&columns%5B2%5D%5Bdata%5D=2&columns%5B2%5D%5Bname%5D=&columns%5B2%5D%5Bsearchable%5D=true&columns%5B2%5D%5Borderable%5D=true&columns%5B2%5D%5Bsearch%5D%5Bvalue%5D=&columns%5B2%5D%5Bsearch%5D%5Bregex%5D=false&columns%5B3%5D%5Bdata%5D=3&columns%5B3%5D%5Bname%5D=&columns%5B3%5D%5Bsearchable%5D=true&columns%5B3%5D%5Borderable%5D=true&columns%5B3%5D%5Bsearch%5D%5Bvalue%5D=&columns%5B3%5D%5Bsearch%5D%5Bregex%5D=false&order%5B0%5D%5Bcolumn%5D=0&order%5B0%5D%5Bdir%5D=asc&start=0&length=10&search%5Bvalue%5D=&search%5Bregex%5D=false&_=1440437669357 HTTP/1.1
Why is my parameters object null, and how can I fix it?
Edit: I also attempted this:
public DataTableResult Get(int draw, int start, int length, column[] columns, order[] order)
{
return new DataTableResult();
}
But I get "Can't bind multiple parameters ('columns' and 'order') to the request's content."
UGH less than 10 minutes later, I need a [FromUri] attribute on the parameters.
public DataTableResult Get([FromUri]DataTableParameters parameters)
{
return new DataTableResult();
}
I am passing back a List of objects to a webapi controller. i need to add 2 more properties, they are both Lists. I am stuck on how to setup my classes.
model/apicontroller
public class DataPoints
{
public string sqft { get; set; }
public string price { get; set; }
}
public class Products
{
public string product { get; set; }
}
public class Data
{
public string Color { get; set; }
public string Name { get; set; }
public IList<DataPoints> DataPoints { get; set; }
public IList<Products> Products { get; set; }
}
public class ExportLegendController : ApiController
{
// POST: api/ExportLegend
[HttpPost]
public PDF Post([FromBody]List<Data> data)
{
here is what I am passing back
This should work as long as your JSON object has properties called dataPoints and products - whereas at the moment they're called data and product (or vice versa of course, you could rename your .NET model.)
I also find IEnumerables are more reliably deserialised.
I have a model which is storing mycustomer new request information.
In another history model i am storing all previous request of the customer.
In view i would like to take new order and also see his previous orders and suggest some food after seeing his previous order.
Here are my models...
public class CustomerFoodModel
{
public DateTime FoodRequestCreated { get; set; }
public string FoodRequestType { get; set; }
...
...
}
public class CustomerHistoryModel
{
public string Name { get; set; }
public DateTime FoodRequestCreated { get; set; }
public string FoodRequestType { get; set; }
...
...
}
Helper.cs file
public static CustomerFoodModel getCustomerDetails(int id) // id is loyalty card number
{
// get details from (cutomer) sql table
//store it in (CustomerFoodModel)
// check if it has previous orders
getCustomerHistoryDetails(id);
....
}
public static CustomerHistoryModel getCustomerHistoryDetails(int id)
{
// get deails from (history) sql table
// store it in (CustomerHistoryModel
}
In my controller, I am passing my (CustomerFoodModel) to the view.
public ActionResult EditCustomerRequest(int id, string name, string date)
{
CustomerFoodModel CRequest = Helper.getCustomerDetails(id);
...
return PartialView("EditCustomerRequest",CRequest);
}
How do I show the (CustomerHistoryModel) in the same view.? Is there possible to include (CustomerHistoryModel) in (CustomerFoodModel)?
Create a new class to wrap both of the model.
public class CustomerFoodModel
{
public CustomerFoodModel CustomerFood { get; set; }
public CustomerHistoryModel CustomerHistory { get; set; }
}
And on your controller
public ActionResult EditCustomerRequest(int id, string name, string date)
{
CustomerFoodModel CRequest = Helper.getCustomerDetails(id);
CustomerHistoryModel CHModel = Helper. getCustomerHistoryDetails(id);
return PartialView("EditCustomerRequest",new CustomerFoodModel(){
CustomerFood = CRequest,
CustomerHistory = CHModel
});
}
I think the best approach is to use a partial view inside the main view. The partial view can call back to another controller to get a new model and pass that model to the partial view. This keeps things better seperated.
Look at this post for a similar issue.
Using partial views in ASP.net MVC 4
Use wrapper class which contain both of class
public class CustomerViewModel
{
public CustomerFoodModel FoodModel { get; set; }
public CustomerHistoryModel HistoryModel { get; set; }
}
You have a few options. I would probably could create a view model that contains both of your models:
public class CustomerViewModel
{
public CustomerFoodModel FoodModel { get; set; }
public CustomerHistoryModel HistoryModel { get; set; }
}
Or, depending on your data structure, you may have multiple history entries per customer:
public class CustomerViewModel
{
public CustomerFoodModel FoodModel { get; set; }
public List<CustomerHistoryModel> HistoryModels { get; set; }
}
Then your getCustomerDetails function would return a CustomerViewModel instead.
Maybe a simple question, but I can't seem to figure it out. Saving a collection to a model when adding a model to the database isn't working. I have a site which uses asp.net MVC and entity framework.
The models:
public class Event
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public ICollection<EventRange> Ranges { get; set; }
}
public class EventRange
{
public int Id { get; set; }
public string RangeName { get; set; }
public string RangeDescription { get; set; }
public int Capacitiy { get; set; }
}
The controller actions:
[HttpPost]
public ActionResult Create(Event model)
{
ICollection<EventRange> eventRanges = new Collection<EventRange>();
var range = new EventRange {RangeName = "testrange", RangeDescription = "test", Capacitiy = 5}
eventRanges.Add(range);
model.Ranges = eventRanges;
db.Events.Add(model);
db.SaveChanges();
return View();
}
public ActionResult Events()
{
return View(db.Events);
}
When setting a breakpoint in the Events action and evaluated the query, the Range isn't saved to the event:
Code Screenshot
Note that that the database created for the eventrange model by EF does save the range:
EF DB Screenshot
Am I doing something wrong?
What if you mark the Ranges property as virtual?
public virtual ICollection<EventRange> Ranges { get; set; }