Parsing Json array to C# Object - c#

I'm building a .NET WebAPI that receives Json through a Post operation. The Json that's being received could look like the following:
{
"site": "00131231201d010231",
"publishTime": 123123123123,
"domains": [
"example.com"
],
"publishedBy": {
"name": "John Doe",
"id": "00211231201d010231"
}
}
I converted my Json response type to C# objects which look like the following:
public class Project
{
[Key]
[JsonPropertyName("site")]
public string Site { get; set; }
[JsonPropertyName("publishTime")]
public long PublishTime { get; set; }
[JsonPropertyName("domains")]
public List<Domain> Domains { get; set; }
[JsonPropertyName("publishedBy")]
public PublishedBy PublishedBy { get; set; }
}
public class PublishedBy
{
[JsonPropertyName("name")]
public string Name { get; set; }
[Key]
[JsonPropertyName("id")]
public string Id { get; set; }
}
public class Domain
{
[Key]
public string Id { get; set; }
public string Name { get; set; }
}
As you can see, my goal is to add the contents to my database. Only when I use List Domains, it gives me an error saying I can't use strings in EFCore when I try to add a migration.
So, I created an object called Domain. But now when I try to deserialize it gives me the following error:
System.Text.Json.JsonException: The JSON value could not be converted to spine_management.Models.Domain.
Does anyone happen to know what type I should make Domains and/or what the best way to deserialize this object is?
EDIT:
I want to keep the domains attribute, I don't want to ignore or delete them.

It's not uncommon to split between two different model structures for interacting with different infrastructure points. In this case your infrastructure points are:
Deserializing JSON input
Persisting data with EF
You can treat the JSON input like a "view model". It's not your core model which maps to EF database entities, but rather just an anemic DTO for deserializing data. For that model, Domains is simply a list of strings:
[JsonPropertyName("domains")]
public List<string> Domains { get; set; }
This view model is local to the application layer, not part of the core domain. Within the application logic, after deserializing the input, you can map it to the domain object. That's where you would translate the list of simple strings into a list of Domain objects. (And translate back in any output operations.)
As long as the mapping logic (which might be made simple by using tools like AutoMapper, though in this case the logic is pretty straightforward and doesn't really necessitate adding more tools) is encapsulated within that application layer, it won't pollute the rest of the domain logic.
Though it may certainly be possible to configure one or both of these tools to work together more smoothly, I often find that a simple translation layer between dependency-specific DTOs and core domain models is much simpler to build and maintain.

I currently use Newtonsoft JSON for serialize and deserializing. I think the reason for this error is you wrote named the string in domain "Name", but it has to be "name". Hope it works!

Related

Customize serialization to JSON to leave some fields

I have a .NET Core API project backed by MongoDB.
I have a sample model class:
public class MyModel
{
[BsonId]
[BsonRepresentation(BsonType.ObjectId)]
public string Id { get; set; }
[BsonElement("aField")]
public string AField { get; set; }
[BsonElement("hiddenField")]
public string HiddenField { get; set; }
}
What I want to achieve is to set the HiddenField to null every time when it is returned as the payload in my controller. I am thinking of a custom JSON serializer but don't know how to do it. Can anyone help?
NB: I don't want to manually set the HiddenField to null in every single controller or action.
Apply JsonIgnore attribute to HiddenField property.
public class MyModel
{
// ... other members
[JsonIgnore]
[BsonElement("hiddenField")]
public string HiddenField { get; set; }
}
Since under the hood ASP.Net Core uses Newtonsoft.Json (aka Json.NET) library to de/serialize JSON payloads, you can control serialization and deserialization with the attributes from that library.
Note that JsonIgnore attribute works in both directions: if a client sends hiddenField to the server, the controller won't populate it in the model.
It also worth noting that starting with ASP.NET Core 3.0, Json.NET won't necessarily be the default mechanism of JSON serialization (see this announcement): in the 3.x versions of ASP.NET Core, one must ensure that integration with Json.NET is plugged in, for current solution to work.
Regarding the architectural discussion in the OP comments, it all depends. Of course, mixing such attributes as JsonIgnore and BsonElement in one class means coupling of two separate concerns: service API and data persistence. However, in small and simple applications, proper separation of concerns might be an overkill, and the most straightforward approach might be a better fit.
I find it easier to create a ViewModel (I tend to use ViewModel as a definition of any model I expose, either by sending it to a server side presentation layer or any external resource REST/etc via JSON/XML/etc).
In this instance, I'd create:
public class MyModelVM
{
public string Id { get; set; }
public string AField { get; set; }
public string HiddenField { get; }
}
HiddenField has no set, so it will always be null. Then set your serialization options and return your JSON.
var myModelVM = new MyModelVM(); // however you want to create/map the values
var json = JsonConvert.SerializeObject(myModelVM,
Newtonsoft.Json.Formatting.None,
new JsonSerializerSettings {
NullValueHandling = NullValueHandling.Include
});
If you didn't map values to MyModelVM, then the resulting JSON would look like:
{
"Id" : null,
"AField" : null,
"HiddenField" : null,
}

Return only a subset of properties of an object from an API

Say I have a database in which I am storing user details of this structure:
public class User
{
public string UserId { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public string PasswordHash { get; set; }
}
I have a data access layer that works with this that contains methods such as GetById() and returns me a User object.
But then say I have an API which needs to return a users details, but not sensitive parts such as the PasswordHash. I can get the User from the database but then I need to strip out certain fields. What is the "correct" way to do this?
I've thought of a few ways to deal with this most of which involve splitting the User class into a BaseClass with non sensitive data and a derived class that contains the properties I would want kept secret, and then converting or mapping the object to the BaseClass before returning it, however this feels clunky and dirty.
It feels like this should be a relatively common scenario, so am I missing an easy way to handle it? I'm working with ASP.Net core and MongoDB specifically, but I guess this is more of a general question.
It seems for my purposes the neatest solution is something like this:
Split the User class into a base class and derived class, and add a constructor to copy the required fields:
public class User
{
public User() { }
public User(UserDetails user)
{
this.UserId = user.UserId;
this.Name = user.Name;
this.Email = user.Email;
}
public string UserId { get; set; }
public string Name { get; set; }
public string Email { get; set; }
}
public class UserDetails : User
{
public string PasswordHash { get; set; }
}
The data access class would return a UserDetails object which could then be converted before returning:
UserDetails userDetails = _dataAccess.GetUser();
User userToReturn = new User(userDetails);
Could also be done using AutoMapper as Daniel suggested instead of the constructor method. Don't love doing this hence why I asked the question but this seems to be the neatest solution and requires the least duplication.
There are two ways to do this:
Use the same class and only populate the properties that you want to send. The problem with this is that value types will have the default value (int properties will be sent as 0, when that may not be accurate).
Use a different class for the data you want to send to the client. This is basically what Daniel is getting at in the comments - you have a different model that is "viewed" by the client.
The second option is most common. If you're using Linq, you can map the values with Select():
users.Select(u => new UserModel { Name = u.Name, Email = u.Email });
A base type will not work the way you hope. If you cast a derived type to it's parent type and serialize it, it still serializes the properties of the derived type.
Take this for example:
public class UserBase {
public string Name { get; set; }
public string Email { get; set; }
}
public class User : UserBase {
public string UserId { get; set; }
public string PasswordHash { get; set; }
}
var user = new User() {
UserId = "Secret",
PasswordHash = "Secret",
Name = "Me",
Email = "something"
};
var serialized = JsonConvert.SerializeObject((UserBase) user);
Notice that cast while serializing. Even so, the result is:
{
"UserId": "Secret",
"PasswordHash": "Secret",
"Name": "Me",
"Email": "something"
}
It still serialized the properties from the User type even though it was casted to UserBase.
If you want ignore the property just add ignore annotation in you model like this, it will skip the property when model is serializing.
[JsonIgnore]
public string PasswordHash { get; set; }
if you want ignore at runtime(that means dynamically).there is build function avilable in Newtonsoft.Json
public class User
{
public string UserId { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public string PasswordHash { get; set; }
//FYI ShouldSerialize_PROPERTY_NAME_HERE()
public bool ShouldSerializePasswordHash()
{
// use the condtion when it will be serlized
return (PasswordHash != this);
}
}
It is called "conditional property serialization" and the documentation can be found here. hope this helps
The problem is that you're viewing this wrong. An API, even if it's working directly with a particular database entity, is not dealing with entities. There's a separation of concerns issue at play here. Your API is dealing with a representation of your user entity. The entity class itself is a function of your database. It has stuff on it that only matters to the database, and importantly, stuff on it that does not matter to your API. Trying to have one class that can satisfy multiple different applications is folly, and will only lead to brittle code with nested dependencies.
More to the point, how are you going to interact with this API? Namely, if your API exposes your User entity directly, then any code that consumes this API either must take a dependency on your data layer so it can access User or it must implement its own class representing a User and hope that it matches up with what the API actually wants.
Now imagine the alternative. You create a "common" class library that will be shared between your API and any client. In that library, you define something like UserResource. Your API binds to/from UserResource only, and maps that back and forth to User. Now, you have completely segregated your data layer. Clients only know about UserResource and the only thing that touches your data layer is your API. And, of course, now you can limit what information on User is exposed to clients of your API, simply by how you build UserResource. Better still, if your application needs should change, User can change without spiraling out as an API conflict for each consuming client. You simply fixup your API, and clients go on unawares. If you do need to make a breaking change, you can do something like create a UserResource2 class, along with a new version of your API. You cannot create a User2 without causing a whole new table to be created, which would then spiral out into conflicts in Identity.
Long and short, the right way to go with APIs is to always use a separate DTO class, or even multiple DTO classes. An API should never consume an entity class directly, or you're in for nothing but pain down the line.

Entity Framework DB first issues loading related entities (ASP.NET web api)

I've been looking for answers for this relatively simple task but with no success. So I thought I'd ask my question here. I have got a simple database with two tables, Books and Authors.
I got my models generated by the ADO.NET entity data model. This is the auto-generated Books model:
public partial class Book
{
public int BookID { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public int ISBN { get; set; }
public int AuthorID { get; set; }
public virtual Author Author { get; set; }
}
And this is the auto-generated Authors model:
public partial class Author
{
public Author()
{
this.Books = new HashSet<Book>();
}
public int AuthorID { get; set; }
public string Name { get; set; }
public virtual ICollection<Book> Books { get; set; }
}
And this is a part of the controller, the method for getting a list of all the books in JSON format.
// api/books
public IQueryable<Book> GetBooks()
{
// return db.Books.Include(x => x.Authors); Don't work
return db.Books;
}
This is my JS for calling the endpoint:
$.getJSON("api/books")
.done(function (data) {
console.log(data);
})
.fail(function (xhr) { console.log(xhr.responseText) });
Nothing fancy, just trying to make a GET request and receiving a list of all the books and their related authors.
This is a portion of the error message:
{"Message":"An error has occurred.","ExceptionMessage":"The 'ObjectContent`1' type failed to serialize the response body for content type 'application/json; charset=utf-8'.","ExceptionType":"System.InvalidOperationException","StackTrace":null,"InnerException":{"Message":"An error has occurred.","ExceptionMessage":"Self referencing loop detected for property 'Author' with type 'System.Data.Entity.DynamicProxies.Author_5968F94A1BBB745A30D62CD59D0AC5F96A198B3F16F0EA2C2F61575F70034886'. Path '[0].Books[0]'.","ExceptionType":"Newtonsoft.Json.JsonSerializationException","StackTrace":"
I have tried preserving object references in JSON but that mangles the response. Is that is the only option?
If you examine the inner exception it says:
Self referencing loop detected for property 'Author'
This tells you that your Author class references back to the parent (i.e. Books or vice versa).
In your web api config (App_Start/WebApiConfig.cs), add this:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Prevent "Self referencing loop detected" error occurring for recursive objects
var serializerSettings = new JsonSerializerSettings()
{
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
};
config.Formatters.JsonFormatter.SerializerSettings = serializerSettings;
}
}
This tells JSON.NET to ignore nested objects referring back to the parent object
adaam's answer is 100% correct but I thought I'd chime in with a bit of advice, but it's too long to fit in a comment so here goes.
Directly serialising Entity Framework objects is generally not a great idea; it's better to use simple DTO-style objects for passing data back to clients.
Of course this is just advice and YMMV :)
The benefits of using DTOs include
Proper decoupling from your Entity Framework objects in your Controllers (you could create a Repository abstraction and use that in your controller, meaning your controller is free from a dependency on Entity Framework and thus more testable)
Simpler serialization control - with Entity Framework you will have difficulty trying to control what public properties are send across the wire to clients when the Entity Framework proxy is directly serialized; typically in DB First the declarations for these properties are in auto-generated files that are re-written each time your edmx changes; threfore it becomes painful to have to maintain non-serialization attributes on the properties you don't want sent across the wire (e.g [IgnoreDataMember], etc.)
If you're planning on accepting models via POST, PUT, etc, then you'll rapidly find that it is a pain (if not impossible) to effectively serialize "inward" directly to the Entity Framework proxies so you'll have to write mapping code anyway; by using a DTO approach you accept that you have to map up-front.
Circular references don't happen therefore you never need to worry about it and more importantly, you don't pay the cost of ignoring it (albeit minor, but the serializer has to do some work to avoid these references)
You can easily perform extra transformations, for example flattening, to better suit the client and/or hide details you don't want sent across the wire.
Example
public class BookDTO
{
public int BookID {get;set;}
public string Title {get;set;}
public string Description {get;set;}
public int ISBN {get;set;}
public string AuthorName{get;set;}
}
public HttpResponseMessage GetBooks()
{
//ideally you'd be using a repository abstraction instead of db directly
//but I want to keep this simple.
var books = db.Books.Select(
book=>new BookDTO(){
BookID=book.BookID,
Title=book.Title,
Description=book.Description,
ISBN=book.ISBN,
AuthorName=book.Author.Name //<-flattening
});
return Request.CreateResponse(HttpStatusCode.OK, books);
}
This produces an array of nice, flat objects for the client to consume without having to expose for example the AuthorID which might to be an internal concept you don't particularly want clients to know.
Once you get the hang of it, you can then look at using something like Automapper which will greatly reduce the maintenance burden, and allow you to perform inline projection in your queries.
It is always best to create your own custom models while returning the data but you just want to use Entity Framework classes then along with ignoring refrenceLoopHandeling you would need disable ProxyCreation from you Entity Model.
Follow these steps :
Step 1 : Like adaam described Put his in WebApiConfig register function:
// Prevent "Self referencing loop detected" error occurring for recursive objects
var serializerSettings = new JsonSerializerSettings()
{
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
};
config.Formatters.JsonFormatter.SerializerSettings = serializerSettings;
Step 2 : Which is most important in my case with latest EF to disable Proxy from EF Contaxt.
Goto: [FILE].edmx file then your [FILE].Context.cs
and add the line below in your constructor..
Configuration.ProxyCreationEnabled = false;
Now you won't have related class results any more..

Restful urls. View model specific

I've been going through this blog and I understand what he is saying, especially regarding the hierarchical structure (walking back along the path).
So
/objects/1/property
Removing property should give you the object with id 1, and removing the id should give you all the objects. Excellent and logical.
But I always expose my data via view models, so,
/objects/list/1 will give me the object list view model of the object with id 1. Or /objects/detail/1 will give me the object detail view model for the object with id 1.
Using this approach I have ended up with a long structure just to get a specific view model! I.e. objects/visualization/analysis/thread. Is this even restful? What I seem to be doing (subconsciously!) is structuring my restful API to match the namespace or module for where this specific view model lives (so in .NET it will be namespace: app.models.object.visualization.analysis).
How best to structure a restful endpoint like this? Is it better to have something like
objects-list/1 and objects-detail/1?
Thanks.
Example:
Sorry, I should have been more clear. I will give a .NET example. Suppose I have a cart class
public class Cart
{
public int CardId { get; set; }
public string CartName { get; set; }
public DateTime Created { get; set; }
public DateTime LastUpdated { get; set; }
public IEnumerable<CartItem> Items { get; set; }
}
With a restful design, I could expose carts as /carts, /carts/1, /carts/1/items and so on. But I always expose view models, not the actual data layer object. I.e.
public class CartListModel
{
public int CartId { get; set; }
public string CartName { get; set; }
}
and
public class CartViewModel
{
public int CartId { get; set; }
public string CartName { get; set; }
public DateTime LastUpdated { get; set; }
public IEnumerable<CartItemViewModel> Items { get; set; }
}
So this way I am only exposing the data that I actually need for a specific purpose. Now at the moment, I am exposing these view models as such /carts/list or /carts/list/1. Also /carts/view and /carts/view/1. So the original question is this restful? Do I infact need a separate endpoint for each view model? So /carts-list and /carts-view, carts-view/1 etc.
Non .NET example
Don't really know what to put here! A view model is a representation of the object, only exposing certain properties necessary to bind to a view.
So suppose my object has the following JSON structure
{
id: 1,
name: 'Cart 1',
lastUpdated: '26-Sep-2014 16:51:23',
items: [
// an array of objects
]
}
For a certain view, like a simple table, I may only need the id and the name. So I expose a restful endpoint that gives me back the following structure
{
id: 1,
name: 'Cart 1'
}
Everything else is unnecessary. For a cart edit page, I will probably need a lot more data than just the id and name. The question is, how do I structure a restful endpoint to expose these different representations of the same object?
URIs are stable
Resources are identified by URIs. The get the object with ID 1, do
GET /objects/1
To get a list of all objects, just
GET /objects
Use content negotiation
What representation of the object 1 is returned by the server is decided by content negotiation. This is done using HTTP headers, not URL path segments or query parameters. Do this:
GET /objects/1
Accept: appliction/vnd.com.example.object.detail+json
By this the client could request something you call the "detail view model".
If the client wants to get the "list view model", you could do
GET /objects/1
Accept: appliction/vnd.com.example.object.list+json
Note
The URL is the same for both requests.
The Accept headers have different values.
Don't use different URIs
Don't do any of these:
GET /objects/1/list: This would request the sub resource called list from object 1.
GET /objects/1/list: This would request another sub resource.
GET /objects/1?model=detail or GET /objects/1?model=list: These are different URIs which identify different resources.
Just try to keep your URL as simple as possible. That means that if your API was a house and you want all clothes of a person named Marie, your URL would be:
API/persons/Marie/clothes
And not:
API/house/persons/Marie/clothes/all
Sorry for the bad examples. Rest is pretty hard to explain.

ResponstDTO with complex Property in ServiceStack

Havin a Response with a complex property, i want to to map to my responseDTO properly. For all basic types it works out flawlessly.
The ResponseDTO looks like this:
public class ResponseDto
{
public string Id {
get;
set;
}
public struct Refs
{
public Genre GenreDto {
get;
set;
}
public Location LocationDto {
get;
set;
}
}
public Refs References {
get;
set;
}
}
Genre and Location are both for now simple classes with simple properties (int/string)
public class GenreDto {
public string Id {
get;
set;
}
public string Name {
get;
set;
}
}
Question:
Is there any way, without changing/replacing the generic unserializer ( and more specific example) (in this example JSON ) to map such complex properties?
One specific difference to the GithubResponse example is, that i cant use a dictionry of one type, since i have different types under references. Thats why i use a struct, but this seems not to work. Maybe only IEnumerable are allowed?
Update
There is a way using lamda expressins to parse the json manually github.com/ServiceStack/ServiceStack.Text/blob/master/tests/ServiceStack.Text.Tests/UseCases/CentroidTests.cs#L136 but i would really like to avoid this, since the ResponseDTO becomes kinda useless this way - since when writing this kind of manual mapping i would no longer us Automapper to map from ResponseDto to DomainModel - i though like this abstraction and "seperation".
Thanks
I used lambda expressions to solve this issue, a more complex example would be
static public Func<JsonObject,Cart> fromJson = cart => new Cart(new CartDto {
Id = cart.Get<string>("id"),
SelectedDeliveryId = cart.Get<string>("selectedDeliveryId"),
SelectedPaymentId = cart.Get<string>("selectedPaymentId"),
Amount = cart.Get<float>("selectedPaymentId"),
AddressBilling = cart.Object("references").ArrayObjects("address_billing").FirstOrDefault().ConvertTo(AddressDto.fromJson),
AddressDelivery = cart.Object("references").ArrayObjects("address_delivery").FirstOrDefault().ConvertTo(AddressDto.fromJson),
AvailableShippingTypes = cart.Object("references").ArrayObjects("delivery").ConvertAll(ShippingTypeDto.fromJson),
AvailablePaypmentTypes = cart.Object("references").ArrayObjects("payment").ConvertAll(PaymentOptionDto.fromJson),
Tickets = cart.Object("references").ArrayObjects("ticket").ConvertAll(TicketDto.fromJson)
});
So this lamda exprpession is used to parse the JsonObject response of the request and map everything inside, even nested ressources. This works out very well and flexible
Some time ago i stumbled upon a similar problem. Actually ServiceStack works well with complex properties. The problem in my scenario was that i was fetching data from a database and was passing the objects returned from the DB provider directly to ServiceStack. The solution was to either create DTOs out of the models returned by the DB provider or invoke .ToList() on those same models.
I'm just sharing some experience with SS but may be you can specify what's not working for you. Is there an exception thrown or something else.

Categories

Resources