I am getting JSON of Form Data from users. Below is the example of JSON Data
{
"Name":"Mike",
"Age":25,
"Gender":"Male",
"Skills":{
".Net":true,
"Mule":""
}
}
I want to save this data in a table (SQL Server). There is no table in the database, I want to define table name before sending this data to sql. Is there any approach to achieve this. Please help.
I suggest using json2csharp to convert the JSON to C# models and alter the names which are not recognized
public class Skills
{
[JsonProperty(PropertyName = ".Net")] //Add JsonProperty to include unclassified names
public bool DotNet { get; set; }
public string Mule { get; set; }
}
public class RootObject10
{
public string Name { get; set; }
public int Age { get; set; }
public string Gender { get; set; }
public Skills Skills { get; set; }
}
then, you can deserialize the json using JsonConvert
using (StreamReader r = new StreamReader(filepath))
{
string json = r.ReadToEnd();
var obj = JsonConvert.DeserializeObject<RootObject10>(json);
}
After this, based on your requirement create single data table or 2 data tables and inject the data
Assuming your question is not about how to translate json into c# object but rather about how to store it in SQL Server while still being able to query it, you can actually work with json data in sql server: https://learn.microsoft.com/en-us/sql/relational-databases/json/json-data-sql-server?view=sql-server-ver15.
I would opt for something like that if I didn’t have schema upfront or I knew it will change often. Then I would create a table called FormData with an Id and Data fields and just stored your JSON in there.
Bear in mind this is likely less performant than defining tables and properly parsing json (which is covered by other answers here) - make sure you make the call after you’ve considered all pros and cons of schema-less storage.
Upd: if you absolutely must create tables at runtime you could potentially run plain SQL DDL statements like ´CREATE TABLE´ using plain ADO.NET
Related
I asked a question a couple of days ago to collect data from MongoDB as a tree.
MongoDB create an array within an array
I am a newbie to MongoDB, but have used JSON quite substantially. I thought using a MongoDB to store my JSON would be a great benefit, but I am just experiencing immense frustration.
I am using .NET 4.5.2
I have tried a number of ways to return the output from my aggregate query to my page.
public JsonResult GetFolders()
{
IMongoCollection<BsonDocument> collection = database.GetCollection<BsonDocument>("DataStore");
PipelineDefinition<BsonDocument, BsonDocument> treeDocs = new BsonDocument[]
{
// my query, which is a series of new BsonDocument
}
var documentGroup = collection.Aggregate(treeDocs).ToList();
// Here, I have tried to add it to a JsonResult Data,
// as both documentGroup alone and documentGroup.ToJson()
// Also, loop through and add it to a List and return as a JsonResult
// Also, attempted to serialise, and even change the JsonWriterSettings.
}
When I look in the Immediate Window at documentGroup, it looks exactly like Json, but when I send to browser, it is an escaped string, with \" surrounding all my keys and values.
I have attempted to create a model...
public class FolderTree
{
public string id { get; set; }
public string text { get; set; }
public List<FolderTree> children { get; set; }
}
then loop through the documentGroup
foreach(var docItem in documentGroup)
{
myDocs.Add(BsonSerializer.Deserialize<FolderTree>(docItem));
}
but Bson complains that it cannot convert int to string. (I have to have text and id as a string, as some of the items are strings)
How do I get my MongoDB data output as Json, and delivered to my browser as Json?
Thanks for your assistance.
========= EDIT ===========
I have attempted to follow this answer as suggested by Yong Shun below, https://stackoverflow.com/a/43220477/4541217 but this failed.
I had issues, that the "id" was not all the way through the tree, so I changed the folder tree to be...
public class FolderTree
{
//[BsonSerializer(typeof(FolderTreeObjectTypeSerializer))]
//public string id { get; set; }
[BsonSerializer(typeof(FolderTreeObjectTypeSerializer))]
public string text { get; set; }
public List<FolderTreeChildren> children { get; set; }
}
public class FolderTreeChildren
{
[BsonSerializer(typeof(FolderTreeObjectTypeSerializer))]
public string text { get; set; }
public List<FolderTreeChildren> children { get; set; }
}
Now, when I look at documentGroup, I see...
[0]: {Plugins.Models.FolderTree}
[1]: {Plugins.Models.FolderTree}
To be fair to sbc in the comments, I have made so many changes to get this to work, that I can't remember the code I had that generated it.
Because I could not send direct, my json result was handled as...
JsonResult json = new JsonResult();
json.Data = documentGroup;
//json.Data = JsonConvert.SerializeObject(documentGroup);
json.JsonRequestBehavior = JsonRequestBehavior.AllowGet;
return json;
Note, that I also tried to send it as...
json.Data = documentGroup.ToJson();
json.Data = documentGroup.ToList();
json.Data = documentGroup.ToString();
all with varying failures.
If I leave as documentGroup, I get {Current: null, WasFirstBatchEmpty: false, PostBatchResumeToken: null}
If I do .ToJson(), I get "{ \"_t\" : \"AsyncCursor`1\" }"
If I do .ToList(), I get what looks like Json in json.Data, but get an error of Unable to cast object of type 'MongoDB.Bson.BsonInt32' to type 'MongoDB.Bson.BsonBoolean'.
If I do .ToString(), I get "MongoDB.Driver.Core.Operations.AsyncCursor`1[MongoDB.Bson.BsonDocument]"
=========== EDIT 2 =================
As this way of extracting the data from MongoDB doesn't want to work, how else can I make it work?
I am using C# MVC4. (.NET 4.5.2)
I need to deliver json to the browser, hence why I am using a JsonResult return type.
I need to use an aggregate to collect from MongoDB in the format I need it.
My Newtonsoft.Json version is 11.0.2
My MongoDB.Driver is version 2.11.1
My method is the simplest it can be.
What am I missing?
I am using .NET Framework and ASP.NET Core to create a REST web Api.
This web api has a call that gets a request model to save data and some call that later retrieves the data.
Most of the data is structured information I need in the backend and it is saved into different fields and tables in the database. On retrieval it is loaded from those tables and returned.
This all works.
However, I now have a requirement where the caller wants to save and later retrieve arbitrary data (lets just say a random json) as one of those fields. I can save and load json from the database that is not a problem, my problem is to build the web api model for my request.
[HttpPost]
public IActionResult Save([FromBody] ApiCallRequestModel request)
{
// ...
}
public sealed class ApiCallRequestModel
{
// structured, well known information
public int? MaybeSomeNumber { get; set; }
[Required]
public string SomeText { get; set; }
[Required]
public SubModel SomeData { get; set; }
// one field of unknown json data
public ??? CustomData { get; set; }
}
I could think of dynamic or maybe even ExpandoObject or JObject to try and I might, but I would like a solution that works because it's best practice, not just because I tried and it didn't fail today with my simple tests.
If everything else fails, I could just make the field a string and tell the client to put serialized json into it. But that's a workaround I would see as a last resort if this question yields no answers.
It has proven to be extremly hard to google this topic, since all words I would use lead me to pages explaining Json serialization of my request model itself. I know how that works and it's not a problem. The mix of structured data and free json is what I cannot find out from a somewhat authorative source.
So what type would you use here, what is the best practice for receiving arbitrary json in one property of your model?
So to sum this up, as suggested I used a JToken from the Json.NET nuget package, since I already had that package in my project.
[HttpPost]
public IActionResult Save([FromBody] ApiCallRequestModel request)
{
// ...
}
public sealed class ApiCallRequestModel
{
// structured, well known information
public int? MaybeSomeNumber { get; set; }
[Required]
public string SomeText { get; set; }
[Required]
public SubModel SomeData { get; set; }
// one field of unknown json data
public JToken CustomData { get; set; }
}
Works like a charm.
Let me preface by saying I'm very new to C# development so if the solution seems obvious I apologize.
I'm getting a JSON string back from a user and I need to filter a list of C# objects based on what the JSON string contains. The JSON can only have fields that my C# model has but I don't know what fields the JSON string will contain. My C# model looks something like this:
public class Enrollment {
public int Year { get; set; }
public int NumEnrolls { get; set; }
public int DaysIntoEnrollment { get; set; }
public string Name { get; set; }
}
The JSON will have one or more of these properties with values to filter out. It could look like this:
{
"Year": ["2020", "2019"],
"Name": ["CourseA", "CourseB"],
"DaysIntoEnrollment": "20"
}
I need to filter my list of Enrollment objects based on the above JSON. So I would want the end result to have all Enrollment objects that don't contain a Year of 2020 or 2019 for example.
I've gotten a filter to work with linq on a single property but my real model has much more properties that can be filtered and I'm looking for a compact solution that will work regardless of which properties are included in the JSON. This is what I have working
public void GetFilteredData(string filters) {
var enrollList = new List<Enrollments>(); // Pretend this contains a list of valid Enrollment data
var json = JObject.Parse(filters); // filters string is in the json format from above
var propsToFilter =
from p in json["Year"]
select p;
var filtered = enrollList.Where(e => !propsToFilter.Contains(e.Year.ToString())));
}
Is there a simple way to do this without manually going through each property like I did above?
Suppose I have a model with 20 fields, and in my index page, I want to list all models that are stored in my database.
In index page, instead of listing all fields of the model, I only to list 3 fields.
So, I make two class:
class CompleteModel {
public int Id { get; set; }
public string Field01 { get; set; }
public string Field02 { get; set; }
public string Field03 { get; set; }
public string Field04 { get; set; }
public string Field05 { get; set; }
...
public string Field20 { get; set; }
}
now, in my Controller, I can use:
await _context.CompleteModel.ToListAsync();
but I feel that it does not seem to be the right way to do it, because I'm getting all fields and using only 3 fields.
So, I made this code:
class ViewModel {
public string Field02 { get; set; }
public string Field04 { get; set; }
public string Field08 { get; set; }
}
var result = _context.CompleteModel.Select(
x => new {
x.Field02,
x.Field04,
x.Field08
}).ToListAsync();
var listResults = new List<IndexViewModel>();
if (result != null)
{
listResults.AddRange(results.Select(x => new IndexViewModel
{
Field02 = x.Field02,
Field04 = x.Field04,
Field08 = x.Field08
}));
}
I think this is a lot of code to do this.
First, I selected all the fields that I want, then, copied everything to another object.
There's a "more directly" way to do the same thing?
Like:
_context.CompleteModel.Select(x => new IndexViewModel { Field02, Field04, Field08 });
You could use AutoMapper to reduce the boiler plate so you're not manually copying field values over.
If you include the AutoMapper NuGet package then you'd need to have the following in your startup somewhere to configure it for your classes:
Mapper.Initialize(cfg => cfg.CreateMap<CompleteModel, ViewModel>());
You could then do something like the following:
var results = await _context.CompleteModel.ToListAsync();
var viewModelResults = results.Select(Mapper.Map<ViewModel>).ToList();
There are a lot of configuration options for the package so do take a look at the documentation to see if it suits your needs and determine the best way to use it if it does.
In my view this is one of the weaknesses of over abstraction and layering. The VM contains the data that is valuable to your application within the context of use (screen, process etc). The data model contains all the data that could be stored that might be relevant. At some point you need to match the two.
Use EF Projection to fetch only the data you need from the database into projected data model classes (using the EF POCO layer to define the query, but not to store the resultant data).
Map the projected classes onto your VM, if there is a naieve mapping, using Automapper or similar. However unless you are just writing CRUD screens a simple field by field mapping is of little value; the data you fetch from your data store via EF is in its raw, probably relational form. The data required by your VM is probably not going to fit that form very neatly (again, unless you are doing a simple CRUD form), so you are going to need to add some value by coding the relationship between the data store and the View Model.
I think concentrating on the count of lines of code would lead to the wrong approach. I think you can look at that code and ask "is it adding any value". If you can delegate the task to Automapper, then great; but your VM isn't really pulling its weight other than adding some validation annotation if you can consistently delegate the task of data model to VM data copying.
I am working on a REST API for a project using Visual Studio 2013 with C# and ASP.NET, and I need some guidance.
When the webpage performs a POST, I am passing along a number of fields as a JSON object. By defining a data transfer object in my C# code, I can easily read the values from the JSON, but only if I define all the fields (with the same name).
Here is my current (working) code:
public class AgencyPostDTO
{
public string AgencyName { get; set; }
public string Address1 { get; set; }
public string Address2 { get; set; }
public string City { get; set; }
public string State { get; set; }
public string ZIP { get; set; }
}
// POST: api/Agency
public string Post(AgencyPostDTO Agency)
{
int success;
success = SQLUpdateAgency(Agency);
if (success < 1)
{
return "Failed";
}
else
{
return "Success";
}
}
So far no problems. I need to pass the data over to a second function, where I will perform some data processing (including converting the data into XML) and send the data/XML to MS SQL using a stored procedure:
public int SQLUpdateAgency(AgencyPostDTO Agency)
{
string xml = Agency.SerializeObject();
... code to call SQL stored procedure ommitted here
}
Now to my problem. I would prefer if I did not have to define the parameters of the data transfer object AgencyPostDTO in the code, and instead the code would just read the incoming JSON and pass it along to the next function, where I create the XML containing everything passed along.
As it works now, if the JSON contains for example an email address field, it will be dropped unless I define it in AgencyPostDTO.
So why do I want to do this? For future ease of maintenance. The users may come and say they want to add additional fields to the web form. I can then simply have our SQL expert add that column to the table, give me the name of it and I add an input field to the HTML form and make sure it is included in the JSON sent over. That way we never have to touch the already written, tested and working code. The new field is simply passed though the whole process.
Can this be done? If so, any suggestions on how?
If you used JSON.NET to handle the deserialisation of your objects then that has support for dynamic properties. Once you'd read your JSON string, you could convert it to a JArray or JObject and from there by using the .Children() call to get a list of all properties to convert it to any XML object you needed.
Have a look here:
Deserialize json object into dynamic object using Json.net