Pass widget data using json and saving to database - c#

I have just come back to this requirement again as I was pulled away from it to do more important requirements at the time.
I have asked a similar question here and the answer has helped. However, in that question, I was passing test data and saving it to the database. I'm unable to figure out how to save the actual widget information however. The link helped me with passing the json successfully.
I receive this message when trying to save the data.
jQuery
function updateWidgetData() {
var items = [];
$('.column').each(function () {
var columnId = $(this).attr('id');
$('.dragbox', this).each(function (i) {
var collapsed = 0;
if ($(this).find('.dragbox-content').css('display') == "none")
collapsed = 1;
//Create Item object for current panel
var item = {
id: $(this).attr('id'),
collapsed: collapsed,
order: i,
column: columnId
};
//Push item object into items array
items.push(item);
});
});
//Assign items array to sortorder JSON variable
var sortorder = { items: items };
$.ajax({
url: "/Handlers/SaveWidgets.ashx",
type: "POST",
contentType: "application/json; charset=uft-8",
dataType: "json",
data: JSON.stringify(sortorder),
success: function (response) {
alert("Passed json");
},
error: function (error) {
alert("Failed passing json.");
}
});
Handler
public void ProcessRequest(HttpContext context)
{
String json = String.Empty;
// you have sent JSON to the server
// read it into a string via the input stream
using (StreamReader rd = new StreamReader(context.Request.InputStream))
{
json = rd.ReadToEnd();
}
// create an instance of YourDataModel from the
// json sent to this handler
SaveWidgetsDAL data = null;
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(SaveWidgetsDAL));
using (MemoryStream ms = new MemoryStream())
{
byte[] utf8Bytes = Encoding.UTF8.GetBytes(json);
ms.Write(utf8Bytes, 0, utf8Bytes.Length);
ms.Position = 0;
data = serializer.ReadObject(ms) as SaveWidgetsDAL;
}
// update the DB and
// send back a JSON response
int rowsUpdated = 0;
foreach (var item in data.wdata)
{
using (SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["dboCao"].ConnectionString))
{
conn.Open();
using (SqlCommand cmd = new SqlCommand("UPDATE tWidgetControl SET SortNo = #SortNo, ColumnId = #ColumnId, Collapsed = #Collapsed "
+ "WHERE UserId = #UserId AND WidgetId = #WidgetId;", conn))
{
cmd.Parameters.AddWithValue("#SortNo", item.SortNo);
cmd.Parameters.AddWithValue("#ColumnId", item.ColumnId);
cmd.Parameters.AddWithValue("#Collapsed", item.Collapsed);
cmd.Parameters.AddWithValue("#UserId", "2");
cmd.Parameters.AddWithValue("#WidgetId", item.WidgetId);
rowsUpdated = cmd.ExecuteNonQuery();
}
conn.Close();
}
}
context.Response.ContentType = "application/json";
context.Response.Write("{ \"rows_updated\": " + rowsUpdated + " }");
}
public bool IsReusable
{
get
{
return false;
}
}
Widgets Data Class
public class SaveWidgetsDAL
{
public List<Widgets> wdata { get; set; }
public SaveWidgetsDAL() { }
public class Widgets
{
[DataMember]
public string SortNo { get; set; }
[DataMember]
public string ColumnId { get; set; }
[DataMember]
public string Collapsed { get; set; }
[DataMember]
public string Title { get; set; }
[DataMember]
public string UserId { get; set; }
[DataMember]
public string WidgetId { get; set; }
}
}
I would imagine that I would need to save the json into a list and then insert/update each widget information into the database. However, I receive the error above when I try this. I'm clearly missing something, but I am not sure what it is. This error occurs in my handler, but the list in the SaveWidgetsDAL is empty, causing the NullReference. I am not sure what I am missing or sure where to go from here. Any help is greatly appreciated!
EDIT 1:
I have changed my database around a bit along with my SaveWidgetsDAL.
SaveWidgetsDAL
[DataContract]
public class SaveWidgetsDAL
{
[DataMember(Name = "items")]
public List<Widgets> wdata { get; set; }
public SaveWidgetsDAL() { }
public class Widgets
{
[DataMember(Name = "order")]
public string SortNo { get; set; }
[DataMember(Name = "column")]
public string ColumnId { get; set; }
[DataMember(Name = "collapsed")]
public string Collapsed { get; set; }
[DataMember(Name = "id")]
public string Title { get; set; }
}
}
Handler (just the foreach)
foreach (var item in data.wdata)
{
using (SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["dboCao"].ConnectionString))
{
conn.Open();
using (SqlCommand cmd = new SqlCommand("UPDATE tWidgetTest SET Title = #Title, SortNo = #SortNo, ColumnId = #ColumnId, Collapsed = #Collapsed "
+ "WHERE UserId = #UserId AND Title = #Title;", conn))
{
cmd.Parameters.AddWithValue("#Title", item.Title);
cmd.Parameters.AddWithValue("#SortNo", item.SortNo);
cmd.Parameters.AddWithValue("#ColumnId", item.ColumnId);
cmd.Parameters.AddWithValue("#Collapsed", item.Collapsed);
cmd.Parameters.AddWithValue("#UserId", "2");
rowsUpdated = cmd.ExecuteNonQuery();
}
conn.Close();
}
}
However, I now get this error when inserting into the database.
I'm able to see that my foreach count is 11, but the Collapsed, SortNo, ColumnId, Title are all null for each item.

The problem seems to be that the data member names specified in your c# data contract do not match the JSON property names in the JSON you are generating. Your JavaScript code generates JSON that looks like
{"items":[{"id":"1","collapsed":"False","order":"1","column":"1"}]}
But these property names are not the property names in your c# classes, and you have not overridden those names. Try something like the following instead:
[DataContract]
public class SaveWidgetsDAL
{
[DataMember(Name="items")]
public List<Widgets> wdata { get; set; }
public SaveWidgetsDAL() { }
[DataContract]
public class Widgets
{
// I was able to figure out which JSON properties to which to map these properties.
[DataMember(Name = "column")]
public string ColumnId { get; set; }
[DataMember(Name = "collapsed")]
public string Collapsed { get; set; }
// However it is unclear how to map these to your JSON.
[DataMember(Name = "sortno")]
public string SortNo { get; set; }
[DataMember(Name = "title")]
public string Title { get; set; }
[DataMember(Name = "userid")]
public string UserId { get; set; }
[DataMember(Name = "widgetid")]
public string WidgetId { get; set; }
}
}
I was able to deduce the correct c# data member names for collapsed: collapsed and column: columnId, however I could not figure out how to map the rest since they don't seem to match up 1-1. You will need to further fix the data member names to make them match exactly.
Update2
In your updated question, you omitted the [DataContract] attribute on the nested Widgets class:
// [DataContract] missing
public class Widgets
{
You need to make sure both the outer and nested classes have this attribute.
Update
This is the part of your code that creates your JSON:
var collapsed = 0;
if ($(this).find('.dragbox-content').css('display') == "none")
collapsed = 1;
//Create Item object for current panel
var item = {
id: $(this).attr('id'),
collapsed: collapsed,
order: i,
column: columnId
};
//Push item object into items array
items.push(item);
var json = JSON.stringify(sortorder);
Thus each object item in your items array contains just these four named properties:
id
collapsed
order
column
The property names you use in your var item = { id: value1, collapsed: value2, ...}; statement are the names that JSON.stringify() writes into the json string. The data member names specified in your c# code must match these names exactly in order to deserialize them with DataContractJsonSerializer. Thus the following c# classes will deserialize those four named properties:
[DataContract]
public class SaveWidgetsDAL
{
[DataMember(Name = "items")]
public List<Widgets> wdata { get; set; }
public SaveWidgetsDAL() { }
[DataContract]
public class Widgets
{
// I was able to figure out which JSON properties to which to map these properties.
[DataMember(Name = "id")]
public string Id { get; set; }
[DataMember(Name = "collapsed")]
public string Collapsed { get; set; }
[DataMember(Name = "order")]
public string Order { get; set; }
[DataMember(Name = "column")]
public string ColumnId { get; set; }
}
}
If you need to transfer additional properties, you need to add them in your var item statement, then add properties with the identical data member name in your Widgets class. To confirm you have correctly matched the names, you can either debug your ProcessRequest() method with Visual Studio and manually examine your json string, or debug log your json string via:
System.Diagnostics.Debug.WriteLine(json);
That will allow you to see the JSON and ensure that your data member names match your JSON property names.

Related

how to convert Json raw object or property cast in to specific model?

public class TransferJson
{
public object json { get; set; }
public int Id { get; set; } = 0;
public bool IsChanged { get; set; } = false;
public string tempData { get; set; } = string.Empty;
}
public partial class Territory
{
public string TerritoryID { get; set; }
public string TerritoryDescription { get; set; }
public int RegionID { get; set; }
}
i have 2 classes one is basically for transfer data and another is for serialize and deserialize data. i am using object to send data over api
however it is not properly deserialize
Territory territory = new Territory();
territory.TerritoryDescription = "Test";
territory.TerritoryID = "Test";
territory.RegionID = 1;
TransferJson objTrf= new TransferJson();
objTrf.json= territory;
objTrf.Id = 1;
objTrf.IsChanged = false;
var SerializeData = JsonConvert.SerializeObject(objTrf);
var DeserializeData= JsonConvert.DeserializeObject<TransferJson>(SerializeData);
var TerritoryData = DeserializeData.json as Territory; // i am getting null here
var Rawobject= DeserializeData.json as object; // i am also not proper getting data here
The json type is object, and it deserialized as dynamic object, so you should to deserialize again DeserializeData.json to get the expected result, like :
Territory territoryData = JsonConvert.DeserializeObject<Territory>(DeserializeData.json.ToString());
I hope you find this helpful.

How to POST list of dictionaries

I would like to post following JSON via API using Restsharp library
{
"id" : "customerID",
"name" : "customerName",
"customKeys" : {
"dataA" : "{\"keyA\": \"valueA\", \"keyB\": \"valueB\"}",
"dataB" : "{\"keyA\": \"valueA\", \"keyB\": \"valueB\"}"
}
}
Actually i made following code which is creating Customer object and everything work correctly beside last fields customKeys....
public class Customer
{
public string id { get; set; }
public string name { get; set; }
public List<Dictionary<string, object>> customKeys { get; set; }
}
Customer customer = new Customer
{
id = id,
name = customerName,
customKeys = ????????????????
};
string json = JsonConvert.SerializeObject(customer);
RestRequest request = newRestRequest("someEndpoint",Method.POST);
request.AddJsonBody(customer);
var response = client.Execute(request);
I just wanted to be sure which data type i should use in following case.
Should i use Dictionary of Dictionaries or just ListOfDictionaries ? Or maybe there is a better and easier way to make that POST call ?
You would use a Dictionary of Dictionaries if your Dictionaries have a special meaning besides just positional placement.
Otherwise, you would be better with a List of Dictionaries.
You can try this:
public class CustomKeys
{
public string dataA { get; set; }
public string dataB { get; set; }
}
public class Customer
{
public string id { get; set; }
public string name { get; set; }
public List<CustomKeys> customKeys { get; set; }
}
Customer customer = new Customer
{
id = id,
name = customerName,
customKeys = new List<CustomKeys>()
{
dataA ="dataA",
dataB ="dataB "
};
};

Error occurred when returning XML - ASP.net web API

I need to get both XML and JSON response data based on the request URL.To achieve my requirement I added this code lines to my API's Application_Start method in global.asax
GlobalConfiguration.Configuration.Formatters.JsonFormatter.MediaTypeMappings.Add(
new QueryStringMapping("type", "json", new MediaTypeHeaderValue("application/json")));
GlobalConfiguration.Configuration.Formatters.XmlFormatter.MediaTypeMappings.Add(
new QueryStringMapping("type", "xml", new MediaTypeHeaderValue("application/xml")));
this code works fine for get JSON. I called API this way,
For JSON output: http://localhost:2751/api/student?type=JSON
For XML output: http://localhost:2751/api/student?type=xml
But when I calling for XML this error will be occurred.
The 'ObjectContent`1' type failed to serialize the response body for
content type 'application/xml; charset=utf-8'.
and this is the inner exception message.
Type 'DeleteAPI.Models.StudentModel' with data
contract name
'StudentModel:http://schemas.datacontract.org/2004/07/DeleteAPI.Models'
is not expected. Consider using a DataContractResolver if you are
using DataContractSerializer or add any types not known statically to
the list of known types - for example, by using the KnownTypeAttribute
attribute or by adding them to the list of known types passed to the
serializer.
This is the part of my model class call Student.
public class StudentModel
{
public int StudentID { get; set; }
public int ProjectID { get; set; }
public string WorkDate { get; set; }
public Nullable<int> WorkingHours { get; set; }
public Nullable<int> Overtime { get; set; }
public string Descriptions { get; set; }
}
Part of Controller class,
namespace DeleteAPI.Controllers
{
public class StudentController : ApiController
{
// GET: api/Student
public ArrayList Get()
{
StudentPersistent tp = new StudentPersistent();
return tp.getStudentAll();
}
}
}
and this is the part of StudentPersistent.class
public class StudentPersistent
{
public ArrayList getStudentAll()
{
ArrayList stdArray = new ArrayList();
MySql.Data.MySqlClient.MySqlDataReader mySQLReader = null;
try
{
string sqlString = "select * from tblStudent";
MySql.Data.MySqlClient.MySqlCommand cmd = new MySql.Data.MySqlClient.MySqlCommand(sqlString, conn);
mySQLReader = cmd.ExecuteReader();
while (mySQLReader.Read())
{
StudentModel dm = new StudentModel();
dm.StudentID = mySQLReader.GetInt32(0);
dm.ProjectID = mySQLReader.GetInt32(1);
dm.WorkDate = mySQLReader.GetString(2);
dm.WorkingHours = mySQLReader.GetInt32(3);
dm.Overtime = mySQLReader.GetInt32(4);
dm.Descriptions = mySQLReader.GetString(5);
stdArray.Add(dm);
}
}
catch (MySqlException x)
{
Console.WriteLine(x.Number);
}
return stdArray;
}
}
How can I solve this error and what is the reason for it?
Try changing the action method to :
[HttpGet]
public HttpResponseMessage Get(int isxmlorJson)
{
StudentPersistent tp = new StudentPersistent();
tp = //Get data from Business Layer
var data = new ObjectContent<StudentPersistent>(tp,
((isxmlorJson== 1) ? Configuration.Formatters.XmlFormatter :
Configuration.Formatters.JsonFormatter));
return new HttpResponseMessage()
{
Content = data
};
}
This is the general way of defining the controllers and the configuration in application_start can be removed .
Problem solved. I added KnownType attribute to my model class.
[KnownType(typeof(DeleteAPI.Models.TaskModel))]
public class StudentModel
{
public int DeveloperID { get; set; }
public int ProjectID { get; set; }
public string WorkDate { get; set; }
public Nullable<int> WorkingHours { get; set; }
public Nullable<int> Overtime { get; set; }
public string Descriptions { get; set; }
}

C# Deserializing JSON using json.net , want to extract array index as a model property

I am successfully deserializing a returned JSON array from a RESTful GET request into my C# plain old object model.
I am using the [JSONProperty foo] annotations to bind the JSON names to my model properties.
The JSON returned looks like this :
[{
"ProductCode": "0129923083091",
"Description": "DIESEL ",
"SalesLitres": 6058.7347,
"SalesValue": 6416.2000
},
{
"ProductCode": "0134039344902",
"Description": "UNLEADED ",
"SalesLitres": 3489.8111,
"SalesValue": 3695.7100
},
...
]
I would like to create something akin to a unique index field within my model which is synthesized based on the order of the appearance of the array items returned from JSON.
For reference, my current annotations (without the indexing property) looks like so :
namespace App8.Models
{
public class ReportRow
{
[JsonProperty("ProductCode")]
public string ProductCode { get; set; } = string.Empty;
[JsonProperty("Description")]
public string Description { get; set; } = string.Empty;
[JsonProperty("SalesLitres")]
public double SalesLitres { get; set; } = 0.0;
[JsonProperty("SalesValue")]
public double SalesValue { get; set; } = 0.0;
}
}
Is there an annotation for this provided by Newtonsoft JSON.net...
Or, is there some code which I can place within getter/setters to manufacture a primary key , in essence ?
Assuming
public class ReportRow {
public int Index { get; set; }
[JsonProperty("ProductCode")]
public string ProductCode { get; set; } = string.Empty;
[JsonProperty("Description")]
public string Description { get; set; } = string.Empty;
[JsonProperty("SalesLitres")]
public double SalesLitres { get; set; } = 0.0;
[JsonProperty("SalesValue")]
public double SalesValue { get; set; } = 0.0;
}
After deserializing the data
var data = JsonConvert.DeserializeObject<List<ReportRow>>(json);
You could use linq select to get indexes.
var indexedData = data.Select((item, index) => {
item.Index = index;
return item;
}).ToList();
Or, if index is not a property on model create a type on the fly with one.
var indexedData = data.Select((item, index) => new {
Index = index,
ReportRow = item
}).ToList();

Parse XML with Linq with multiple child elements

This is my first question on SO, please let me know if I am doing anything wrong!
I am trying to parse an XML similar to this:
<LiveUpdate>
<CityID>F0A21EA2</CityID>
<CityName>CityTown</CityName>
<UserName>john</UserName>
<ApplicationDetails>
<ApplicationDetail
Application="AC"
Licensed="true"
Version="2015.2"
Patch="0001"
/>
<ApplicationDetail
Application="AP"
Licensed="true"
Version="2015.2"
Patch="0002"
/>
</ApplicationDetails>
</LiveUpdate>
I have classes that look like this:
public class Client
{
public string cityID { get; set; }
public string cityName { get; set; }
public string userName { get; set; }
public List<Apps> appList { get; set; }
}
public class Apps
{
public string app { get; set; }
public string licensed { get; set; }
public string version { get; set; }
public string patch { get; set; }
}
I need to be able to have a client class with a list of all the application details to be iterated over.
So far the best I've come up with is:
XDocument xml = XDocument.Load(#"C:\blah\Desktop\1.xml");
var liveUpdate = xml.Root;
var clients = (from e in liveUpdate.Elements()
select new Client()
{
cityID = e.Element("CityID").Value,
cityName = e.Element("CityName").Value,
userName = e.Element("UserName").Value,
appList = e.Elements("ApplicationDetails")
.Select(a => new Apps()
{
app = a.Element("Application").Value,
licensed = a.Element("Licensed").Value,
version = a.Element("Version").Value,
patch = a.Element("Patch").Value
}).ToList()
});
However, I'm currently running into an error that says Object reference not set to an instance of an object.
I've seen some similar examples on here, but not that deal with data before the multiple children.
I'm fairly new to XML and Linq so any help here would be greatly appreciated!
Your XML only contains one LiveUpdate tag, so rather than iterating over all of the elements inside of it, you just want to look at the Root element.
In ApplicationDetails, Application, Licensed and such are attributes, not elements. Use .Attribute() to access them.
ApplicationDetails is a single tag, and inside it you have ApplicationDetail tags.
There is no DateTime element in your LiveUpdate tag.
This works:
var liveUpdate = xml.Root;
var e = liveUpdate;
var clients = new Client()
{
cityID = e.Element("CityID").Value,
cityName = e.Element("CityName").Value,
userName = e.Element("UserName").Value,
//dateTime = e.Element("DateTime").Value,
appList = e.Element("ApplicationDetails").Elements("ApplicationDetail")
.Select(a => new Apps()
{
app = a.Attribute("Application").Value,
licensed = a.Attribute("Licensed").Value,
version = a.Attribute("Version").Value,
patch = a.Attribute("Patch").Value
}).ToList()
};
Since you have already defined a class into which you wish to deserialize, you can use XmlSerializer to deserialize it for you.
First, let's rename some of your property names to more closely match the XML and c# naming conventions:
[XmlRoot("LiveUpdate")]
public class Client
{
public string CityID { get; set; }
public string CityName { get; set; }
public string UserName { get; set; }
[XmlArray("ApplicationDetails")]
[XmlArrayItem("ApplicationDetail")]
public List<Apps> AppList { get; set; }
}
public class Apps
{
[XmlAttribute]
public string Application { get; set; }
[XmlAttribute]
public bool Licensed { get; set; }
[XmlAttribute]
public string Version { get; set; }
[XmlAttribute]
public string Patch { get; set; }
}
Then add the following extension methods:
public static class XmlSerializationHelper
{
public static T LoadFromXML<T>(this string xmlString)
{
using (StringReader reader = new StringReader(xmlString))
{
object result = new XmlSerializer(typeof(T)).Deserialize(reader);
if (result is T)
{
return (T)result;
}
}
return default(T);
}
public static T LoadFromFile<T>(string filename)
{
using (var fs = new FileStream(filename, FileMode.Open))
{
object result = new XmlSerializer(typeof(T)).Deserialize(fs);
if (result is T)
{
return (T)result;
}
}
return default(T);
}
}
Now you can deserialize from your XML file as follows:
string fileName = #"C:\blah\Desktop\1.xml";
var client = XmlSerializationHelper.LoadFromFile<Client>(fileName);
I manually updated your Client class to map correctly to the provided XML, but if you wanted to do it automatically, see here: Generate C# class from XML.

Categories

Resources