public class Product
{
public int Id { get; set; }
public string ProductName { get; set; }
public int Quantity { get; set; }
}
public IActionResult Index()
{
var products = new List<Product>
{
new Product{Id = 1, ProductName= "Kulaklik", Quantity = 4},
new Product{Id = 2, ProductName= "Şarj Kablosu", Quantity = 6},
new Product{Id = 3, ProductName= "Akilli Saat", Quantity = 5}
};
string data = JsonSerializer.Serialize(products);
// return View();
TempData["x"] = 5;
ViewBag.x = 5;
ViewData["x"] = 5;
return RedirectToAction("Index2");
}
public IActionResult Index2()
{
var data = TempData["products"].ToString();
List<Product> products = JsonSerializer.Deserialize<List<Product>>(data);
return View();
}
I have an Asp.Net Core Mvc project.
I want to send data to another Action with JsonSerializer class.
But among the overloads of the Serializer method there is no method that expects only a single value. I wonder what package I need to add for Visual Studio?
serialize has a red line under it
You probably have installed both - Newtonsoft.Json and System.Text.Json serializers. Newtonsoft.Json.JsonSerializer.Serialize doesnt have an overload with one argument and it causes an error. So you have to use a namespace to use anther serializer
string data = System.Text.Json.JsonSerializer.Serialize(products);
Related
I am creating a nested custom type with primitive datatypes.
I am having a Web APi that returns the data in JSON.
using json2csharp.com, I am generating classes for the same.
I have decorated the primitive datatypes in all classes with DataMember and the types with DataContract.
I am using the following code for deserialization:
var resp = httpClient.GetAsync("http://ACTUAL_API_URI").Result;
var res = await resp.Content.ReadAsStringAsync();
var serializer = new DataContractJsonSerializer(typeof(RootObject));
byte[] byteArr= Encoding.ASCII.GetBytes(res);
var ms = new MemoryStream(byteArr);
var deserializedObj= (RootObject)serializer.ReadObject(ms);
I am not getting any exception. but the deserializedObj has null values for all the properties.
Any suggestions ?
You have a couple mistakes.
You returns collection of elements and try to deserialize one element instead collection
public IEnumerable<SampleData> Get()
{
return new SampleData[]
{
new SampleData()
{
Value = 100,
NestedTypeObject1 = new NestedType1()
{
ID = 101,
BD = "Description#1",
UD = "Description#2"
},
NestedTypeObject2 = new NestedType2()
{
Date = DateTime.Now.ToString(),
S1 = "S1 String",
S2 = "S2 String"
}
}
};
}
so you just change your code to
var serializer = new DataContractJsonSerializer(typeof(List<RootObject>));
var deserializedObj= (List<RootObject>)serializer.ReadObject(ms);
You have different model names between service side and client side, just you your SampleData model and all will be good. You must to rename MyNestedType1 to NestedTypeObject1 or add name to DataContractAttribute, e.g:
[DataContract(Name = "NestedTypeObject1")]
public class MyNestedType1
{
[DataMember]
public int Id { get; set; }
[DataMember]
public string BD { get; set; }
[DataMember]
public string UD { get; set; }
}
It belongs for property names too.
I am trying to parse a wikipedia api which contain the short text of an article.I am using ASP.Net MVC for coding. My wikipedia api is https://en.wikipedia.org/w/api.php?format=json&action=query&prop=extracts&exlimit=max&explaintext&exintro&titles=Berlin&redirects= which is in json formatted. At present what I have done is - inside the Model I created a folder named Wiki, and inside it I created four class named Limits.cs, Pageval.cs, Query.cs, Rootobject.cs.
public class Limits
{
public int extracts { get; set; }
}
public class Pageval
{
public int pageid { get; set; }
public int ns { get; set; }
public string title { get; set; }
public string extract { get; set; }
}
public class Query
{
public Dictionary<string, Pageval> pages { get; set; }
}
public class Rootobject
{
public string batchcomplete { get; set; }
public Query query { get; set; }
public Limits limits { get; set; }
}
Now in the controller class I created a WebApi 2 contrller to make the model object show on the web. In this case I am very new in handling this situation because I am new at MVC. I am trying to parse in this way but it is not working at all.
public class WikiController : ApiController
{
// GET: api/Wiki
// GET: api/Wiki/5
public string GetShortText(string name)
{
string result;
using (WebClient client = new WebClient())
{
var response = client.DownloadString("https://en.wikipedia.org/w/api.php?format=json&action=query&prop=extracts&exlimit=max&explaintext&exintro&titles=" + name + "&redirects=");
var responseJson = JsonConvert.DeserializeObject<Rootobject>(response);
var firstKey = responseJson.query.pages.First().Key;
var extract = responseJson.query.pages[firstKey].extract;
try
{
Regex regex = new Regex(#".(?<=\()[^()]*(?=\)).(.)");
string.Format("Before:{0}", extract);
extract = regex.Replace(extract, string.Empty);
string result1 = String.Format(extract);
result = Regex.Replace(result1, #"\\n", " ");
}
catch (Exception)
{
result = "Error";
}
}
return result;
}
The Routconfig is-
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
You can do a couple of things. You can use attribute routing or you can define a route for your custom method. The reason it does not map at the moment is that you do not have a route that defines your parameter. So going the route way you can define
routes.MapRoute(
name: "Wiki",
url: "api/wiki/getshorttext/name",
defaults: new { controller = "Wiki", action = "GetShortText", name = UrlParameter.Optional }
)
;
On a side note as you are performing a I/O bound operation I would suggest making your action async using async and await feature of .net. This way you won't block any thread while you waiting for Wikipedia to respond. Also HttpClient offers a DownloadStringAsync which is awaitable. Have a look at async and await
I'm trying to deserialize a BSON HTTP Response Message from a Web API call into a custom type.
using (HttpClient client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:1234");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/bson"));
HttpResponseMessage result;
result = await client.GetAsync("/endpoint/");
MediaTypeFormatter[] formatters = new MediaTypeFormatter[] {
new BsonMediaTypeFormatter()
};
if (result.IsSuccessStatusCode)
{
try
{
RootObject res = await result.Content.ReadAsAsync<RootObject>(formatters);
}
catch (Exception e)
{
}
}
I know the Web API is returning BSON, I checked through Fiddler and the above code actually does deserialize most things correctly in the RootObject. It appears that all of the derived classes are not being deserialized and are just being input into the object as null. Here is an example of a derived class that is not being deserialized.
RootObject.Events.Teams.Linescores
RootObject
[DataContract(Namespace = "", Name = "RootObject")]
[Serializable]
public class RootObject: infoBase
{
[DataMember(EmitDefaultValue = false, Order = 30)]
[JsonProperty(NullValueHandling = NullValueHandling.Ignore, Order = 30)]
public IEnumerable<eventInfo> events { get; set; }
public RootObject() { }
}
Events Object
[DataContract(Namespace = "", Name = "event")]
[Serializable]
[KnownType(typeof(subEventTeam))]
public class eventInfo : infoBase
{
[DataMember(EmitDefaultValue = false, Order = 170)]
[JsonProperty(NullValueHandling = NullValueHandling.Ignore, Order = 170)]
public List<eventTeamBase> teams { get; set; }
public eventInfo() { }
}
Teams Base and Specific Team Type
[DataContract(Namespace = "", Name = "team")]
[Serializable]
[KnownType(typeof(bbLinescoreInfo))]
public class eventTeamBase : infoBase {
[DataMember(Order = 20)]
[JsonProperty(Order = 20)]
public string location { get; set; }
[DataMember(Order = 30, EmitDefaultValue = false)]
[JsonProperty(Order = 30, NullValueHandling = NullValueHandling.Ignore)]
public string nickname { get; set; }
[DataMember(EmitDefaultValue = false, Name = "linescores", Order = 130)]
[JsonProperty(NullValueHandling = NullValueHandling.Ignore, Order = 130)]
public IEnumerable<linescoreBase> linescores { get; set; }
public eventTeamBase() { }
}
[DataContract(Namespace = "", Name = "team")]
[Serializable]
public class subEventTeam : eventTeamBase
{
public subEventTeam () { }
}
Linescore Base and Specific Object
[DataContract(Name = "linescores", Namespace = "")]
[Serializable]
[KnownType(typeof(subLinescoreInfo))]
public class linescoreBase : infoBase
{
public bool isProcessing = false;
public int teamId { get; set; }
public linescoreBase() { }
}
[DataContract(Name = "linescores", Namespace = "")]
[Serializable] public class subLinescoreInfo : linescoreBase
{
[DataMember]
public int inning { get; set; }
[DataMember]
public int? score { get; set; }
public subLinescoreInfo() { };
}
Here is the deserialized (and then re-serialized) part of the response that isn't working output into JSON.
{
"status":"OK",
"recordCount":1,
"RootObject":[
{
"events":[
{
"teams":[
{
"location":"Tallahassee",
"nickname":"Razors",
"linescores":[
{},{},{},{},{},{},{},{}]
}
}
}
}
So as you can see, it is filling in some information correctly (There is a lot more, I've cut down significantly just to illustrate the problem). But the linescores are returning null. As mentioned, the data is returning correctly and it is not null.
I feel like I'm doing something wrong with the known types and I've tried numerous combinations of putting them in different places and the results don't change. Any help would greatly appreciated.
After much searching and trying wrong things, I found a similar solution in another thread.
JSON Solution
I solved this by doing pretty much that exact same thing but with BSON instead of JSON.
This is the code that I needed to add in the global config file of the Web API
BsonMediaTypeFormatter bsonFormatter = new BsonMediaTypeFormatter();
bsonFormatter.SerializerSettings.TypeNameHandling = TypeNameHandling.Objects;
bsonFormatter.AddQueryStringMapping("accept", "bson", "application/bson");
GlobalConfiguration.Configuration.Formatters.Add(bsonFormatter);
And this code went into the client.
BsonMediaTypeFormatter bsonFormatter = new BsonMediaTypeFormatter();
bsonFormatter.SerializerSettings.TypeNameHandling = TypeNameHandling.Objects;
MediaTypeFormatter[] formatters = new MediaTypeFormatter[] {
bsonFormatter
};
Everything else remained the same and was deserialized without incident.
What is the right way to serve OData-queryable GET requests in ASP.NET Web Api? That may sound like a "what is better" question, but it should be a "what does work" question.
Some assumptions:
To enable OData-querying, you have to put the Queryable attribute to the action method that returns IQueryable<Model>. Therefore, you have to expose the domain model?
The domain model uses Entity Framework 5 and has navigation properties. The XML and Json Serializers do not like the EF proxies, so you have to disable them for OData queries?
The serializers pick up the navigation properties and serve them to the user.
So if I have a Category type that has navigation properties for parent and children, the serializers complain that I have cyclic references, and I cannot get rid of this error.
I have read that I should use DTOs, but HOW? How can I provide a IQueryable<DTOModel> to the user that will create the appropriate SQL for the database? Remember, I want to use $filter and the like.
I just want to give the user a filterable list of Model objects without the serialized navigation properties.... but HOW?
You don't have to expose IQueryable<> - you can create a method that accepts an instance of ODataQueryOptions and process this yourself. Here's a code sample that does most of what you require. It should be more than enough for you to work out the solution that works best for you. This method will also allow you to keep your EF proxy classes.
using System.Web.Http.OData;
using System.Web.Http.OData.Builder;
using System.Web.Http.OData.Query;
[ActionName("Dto")]
public IList<DtoModel> GetDto(ODataQueryOptions<DtoModel> queryOptions)
{
var data2 = DatabaseData();
//Create a set of ODataQueryOptions for the internal class
ODataModelBuilder modelBuilder = new ODataConventionModelBuilder();
modelBuilder.EntitySet<Model>("Model");
var queryContext = new ODataQueryContext(
modelBuilder.GetEdmModel(), typeof(Model));
var newQueryOptions = new ODataQueryOptions<Model>(queryContext, Request);
var t = new ODataValidationSettings() { MaxTop = 25 };
var s = new ODataQuerySettings() { PageSize = 25 };
newQueryOptions.Validate(t);
IEnumerable<Model> results =
(IEnumerable<Model>)newQueryOptions.ApplyTo(data2, s);
int skip = newQueryOptions.Skip == null ? 0 : newQueryOptions.Skip.Value;
int take = newQueryOptions.Top == null ? 25 : newQueryOptions.Top.Value;
IList<Model> internalResults = results.Skip(skip).Take(take).ToList();
// map from Model to Dto here using AutoMapper
AutoMapper.Mapper.CreateMap<Model, DtoModel>();
IList<DtoModel> webResults =
AutoMapper.Mapper.Map<IList<Model>, IList<DtoModel>>(internalResults);
return webResults;
}
The data used in the example is a simple Queryable set of data:
private IQueryable<Model> DatabaseData()
{
return (
new Model[] {
new Model() { id = 1, name = "one", type = "a" },
new Model() { id = 2, name = "two", type = "b" },
new Model() { id = 3, name = "three", type = "c" },
new Model() { id = 4, name = "four", type = "d" },
new Model() { id = 5, name = "five", type = "e" },
new Model() { id = 6, name = "six", type = "f" },
new Model() { id = 7, name = "seven", type = "g" },
new Model() { id = 8, name = "eight", type = "h" },
new Model() { id = 9, name = "nine", type = "i" }
})
.AsQueryable();
}
These are the test classes:
public class Poco
{
public int id { get; set; }
public string name { get; set; }
public string type { get; set; }
}
public class DtoModel
{
public int id { get; set; }
public string name { get; set; }
public string type { get; set; }
}
public class Model
{
public int id { get; set; }
public string name { get; set; }
public string type { get; set; }
public virtual ICollection<Poco> Pocos { get; set; }
}
I need some help...
I have my entity that i have create manually.
public class Project()
{
public Project Data {get;set;}
public string ProjectID { get; set; }
public string AreaID { get; set; }
public string Country { get; set; }
}
Where property "Project" is the the table created by SQLmetal.
I have also created my class, with SQLmetal, wish there have there own entity.
Now i trying to parse between them in the constructor like:
public Project()
{
ProjectID = Data.ProjectID;
AreaID = Data.AreaID;
Country = Data.Country;
}
But when I use
projects.Select(p => new Project { Data = p });
the Data property in the constructor is null.
Any idea why? and how will I solve this the better way?
Yes, because the initializer
var x = new Project { Data = p };
is equivalent to
var x = new Project();
x.Data = p;
The Data property is set AFTER the constructor.
You can solve it by creating a constructor that takes Data as a parameter
public Project(Data data)
{
this.Data = Data;
ProjectID = Data.ProjectID;
AreaID = Data.AreaID;
Country = Data.Country;
}
and call the constructor
projects.Select(p => new Project(p));