I'm currently working on a .NET client for the Zoho Books API in order to integrate some data within my organization. I have been struggling with deserializing the json returned by the API. The problem has been because of inheritance and varying property names. I think I'm looking at creating a custom converter in order to avoid creating response types for every model for the sake of a few varying fields.
I was able to create a custom converter that works for parent responses which look like this:
{
"code" : 0,
"message" : "success",
"invoice" : { // This field varies by model
"invoice_id" : "..."
}
}
I have created a gist for this custom converter.
One of the issues with the custom converter is that when I pass the generic return type down from the web client, I need it in either in the base response format or the paginated response format, and generics are failing me here. My converter doesn't work for paginated responses.
I defined my base type of ZohoBooks Response as so:
namespace ZohoBooks4Net.Responses
{
public class ZohoBooksResponse<T> : IZohoBooksResponse<T>
{
/// <summary>
/// Zoho Books error code. This will be zero for a success response and non-zero in case of an error.
/// </summary>
[JsonProperty("code")]
public int Code { get; set; }
/// <summary>
/// Message for the invoked API.
/// </summary>
[JsonProperty("message")]
public string Message { get; set; }
/// <summary>
/// Comprises the invoked API’s Data.
/// </summary>
public T Resource { get; set; }
}
}
Resource is what I'm calling the third field in the response.
However, when the response returns as paginated, it adds another field.
{
"code": 0,
"message": "success",
"contacts": [
{ "..." }
],
"page_context": {
"page": 1,
"per_page": 200,
"has_more_page": false,
"applied_filter": "Status.All",
"sort_column": "contact_name",
"sort_order": "D"
}
}
So I created this object that describes it:
namespace ZohoBooks4Net.Responses.PaginatedResponses
{
public class PaginatedResponse<T> : ZohoBooksResponse<T>, IPaginatedResponse<T>
{
[JsonProperty("page_context")]
public PageContext Context { get; set; }
}
public class PageContext
{
[JsonProperty("page")]
public int Page { get; set; }
[JsonProperty("per_page")]
public int PerPage { get; set; }
[JsonProperty("has_more_page")]
public bool HasMorePage { get; set; }
}
}
If anyone has any solutions I would really appreciate it.
Books already hosted .Net library in github. In Subscription java client, page context and resources handled separately.
Have you tried using the json2csharp web application tool? It will create the classes needed from your JSON response and a root object which can be used with the Newtonsoft JsonCovnert's DeserializeObject method.
Taking a referenced post from a commenter, I implemented the ReadJson method created by poster of the article. This solved my issue. Here's a link to DynamicPropertyNameConverter on Github Gist.
Related
I'm using Swagger.AspNetCore to document my api. So far i was happy to use xml comments to generate response model examples until i reach the point when i've got to document embeded object. So i have simple model:
public class SummaryResult
{
/// <summary>Total Cost.</summary>
/// <value>Total Cost.</value>
/// <example>6433.2</example>
public double TotalCost { get; set; }
/// <summary>Owner.</summary>
public Owner Owner { get; set; }
}
public class Owner
{
/// <summary>Owner Name.</summary>
/// <value>Owner Name.</value>
/// <example>Michael</example>
public string Name { get; set; }
}
And Swagger UI document it only for TotalCost, Owner property just skipped whatever i do. Does anyone have a clue why this can happen? And how to fix it.
I know how to deal with List - just put on top xml comment like <list></list> but it's not my case.
Thank you
I just tested this and it shows fine on my end:
http://swagger-net-test.azurewebsites.net/swagger/ui/index#/ActionFilter/ActionFilter_Get
Here is how that looks like on the model tab:
As you can see in the image it does show the summary and the example value.
Here is the code:
https://github.com/heldersepu/Swagger-Net-Test/blob/master/Swagger_Test/Controllers/ActionFilterController.cs#L29
Educated guess there could be something else removing those elements.
Swagger generates incorrect URL when model extracted from query string has a dictionary as one of its properties. How to tell Swagger to change format of the dictionary in the URL or to define input parameters schema manually, without auto-generation? Tried to use Swashbuckle and NSwag.
Controller
public class RecordsController : ControllerBase
{
[HttpGet]
[Route("services/records")]
public async Task<IActionResult> Records([FromQuery] QueryModel queryModel)
{
return null;
}
}
Input Model - Query String
public class QueryModel
{
public int Page { get; set; }
public int Count { get; set; }
public Dictionary<Columns, string> Conditions { get; set; }
}
Swagger UI shows this format for "Conditions" property on Query Model
{
"UserId": "string",
"GroupId": "string",
"RecordId": "string"
}
Swagger generated URL - Open API v2 - will not be bound to "Conditions"
/services/records?Page=0&Count=5&Conditions={"UserId":"1"}
Swagger generated URL - Open API v3 - will not be bound to "Conditions"
/services/records?Page=0&Count=5&UserId=1
Custom URL - works as expected and initializes "Conditions" with { "UserId", "1" }
/services/records?Page=0&Count=5&Conditions[UserId]=1
Question
How to enforce Swagger to render URL like PropertyName[Key]=Value for the property of type Dictionary?
Alternative question
Not a solution, but if I define default value for my input parameter this way, Swagger creates correct URL.
{
"Conditions[UserId]": "1",
"Conditions[GroupId]": "2"
}
URL is correct now and is properly bound to the model
/services/records?Page=0&Count=5&Conditions[UserId]=1&Conditions[GroupId]=2
Is there a way to change default value displayed in Swagger for Dictionary input type?
You will need to set the query style deepObject for the query definition
This is currently supported by NSwag through SwaggerParameterStyle for which you will set value deepObject.
I was also curious how to do this without NSwag, so I took a look at https://editor.swagger.io/
Here you can provide it your static json swagger and it will generate you a server if you want to see a different way of creating the same setup
Sample model for dictionary
[DataContract]
public partial class Dictionary : IEquatable<Dictionary>
{
/// <summary>
/// Gets or Sets Word
/// </summary>
[DataMember(Name="word")]
public string Word { get; set; }
/// <summary>
/// Gets or Sets Define
/// </summary>
[DataMember(Name="define")]
public string Define { get; set; }
Sample Controller
/// <summary>
/// Get word definition
/// </summary>
/// <remarks>Get me the word definitions</remarks>
/// <param name="dictionary">Status values that need to be considered for filter</param>
/// <response code="200">successful operation</response>
[HttpGet]
[Route("/v2/book")]
[ValidateModelState]
[SwaggerOperation("BookGet")]
public virtual IActionResult BookGet([FromQuery][Required()]Dictionary dictionary)
Raw Swagger example query
/book:
get:
summary: Get word definition
description: Get me the word definitions
parameters:
- name: dictionary
in: query
description: Status values that need to be considered for filter
required: true
style: deepObject
schema:
type: object
properties:
word:
type: string
define:
type: string
Look at deepObject style in https://swagger.io/specification/
I'm currently implementing dependency injection in an existing ASP.NET Web API project using the Unity container.
I already manage to inject my service classes into my API controller by configuring a dependency resolver.
But for a controller function, I have to use a Data Transfer Object (DTO).
In that object, I can't find how to use my model contracts.
Here is the Web API controller method:
[HttpPost]
[Route("api/application/save")]
public IHttpActionResult SaveApplication(ApplicationUpdateDTO applicationUpdate)
{
// Inner code calling service methods expecting IApplication and
// collections of ITag as parameters.
}
And here is the DTO definition:
public class ApplicationUpdateDTO
{
public IApplication Application { get; set; }
public IEnumerable<int> DeletedTagIds { get; set; }
public IEnumerable<ITag> AddedTags { get; set; }
public IEnumerable<int> DeletedPlatformIds { get; set; }
public IEnumerable<ITag> AddedPlatforms { get; set; }
}
As a result, the DTO itself is initialized, but not the properties that are all null.
I understand why the properties cannot be set : the interfaces cannot be instanciated and it doesn't have any clue of which classes to use for that. But my Unity container does, thanks to the registration.
Is it possible to use this "link" somehow to initialize the DTO properties?
Is there a better way do this?
Notes:
If I use implementations of my interfaces in the DTO, it obviously works fine.
The controller method receives a JSON object that is identical to my DTO.
edit
I also tried the implementation of a ModelBinder by referring to this post.
But for the line about the ValueProviderResult, I got a null value.
For convenience, here is the response from Todd in the other question:
public class CreateSomethingModelBinder : IModelBinder
{
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
string key = bindingContext.ModelName;
ValueProviderResult val = bindingContext.ValueProvider.GetValue(key);
if (val != null)
{
string s = val.AttemptedValue as string;
if (s != null)
{
return new CreateSomething(){Title = s; UserId = new Guid(ControllerContext.HttpContext.Request.Headers["userId"]);}
}
}
return null;
}
}
The small difference I got from the response of the question, is the usage of the System.Web.Http.ModelBinding.IModelBinder instead of the MVC one.
As requested, here are exerpts of my interfaces.
The IApplication interface:
public interface IApplication
{
/// <summary>
/// Identifier of the application.
/// </summary>
int Id { get; set; }
/// <summary>
/// Name of the application.
/// </summary>
string Name { get; set; }
/// <summary>
/// Version of the application.
/// </summary>
string Version { get; set; }
/// <summary>
/// Tags associated to the application.
/// </summary>
ICollection<ITag> Tags { get; }
}
The ITag interface:
public interface ITag
{
/// <summary>
/// Identifier of the tag.
/// </summary>
int Id { get; set; }
/// <summary>
/// Identifier of the application to which the tag is linked.
/// </summary>
int ApplicationId { get; set; }
/// <summary>
/// Value of the tag.
/// </summary>
string Value { get; set; }
}
An example of JSON:
{
"marketApplication": {
"Id": 20,
"Name": "MyApplication",
"Version": "2.0"
},
"deletedTagIds": [],
"addedTags": [
{
"Id": 0,
"Value": "NewTag"
}
],
"deletedProgramIds": [],
"addedPrograms": [
{
"Id": 0,
"Name": "x86"
}
]
}
Dependency Injection is the practice of composing graphs of loosly coupled components. Components are the classes in your system that contain behaviour.
Dependency Injection is not meant to build up objects that merely contain data. Using Dependency Injection we build an graph of components. After that graph has been build (using constructor injection), we pass runtime data through this graph using method calls.
Every time you try to use Dependency Injection or an DI container (like Unity) for anything else, you will get into trouble. So although your question indicates that you want to do this with Unity, Unity should be left out of the equation (for this particular case).
As others already stated, the building of Data Transfer Objects (DTOs) that come in through the request is the job of Web API's Model Binder. The default Model Binders can't deserialize interfaces for you, which is quite obvious; to what implementation should they deserialize?
Although you can replace the default model binder, you should take a step back and look closely at what it is you are trying to achieve. You are abstracting away data. Hiding a DTO behind an abstraction makes usually little sense, since interfaces are meant to abstract behavior.
So instead of using interfaces, it is usually much better to use concrete classes instead.
it would save me the copy from a "sub-DTO" to a concrete one manually
Instead of doing that, a simpler approach would be to use composition. You can compose DTOs out of smaller DTOs. That would save you from having to do the copying completely.
by using the matching type registered in my Unity container.
This assumes that those DTOs should be registered in the container, but again, an DI container should not hold any runtime data. This should be kept out. Or as stated here:
Don't inject runtime data into application components during construction; it causes ambiguity, complicates the composition root with an extra responsibility and makes it extraordinarily hard to verify the correctness of your DI configuration. My advice is to let runtime data flow through the method calls of constructed object graphs.
Update
The idea of composition is simple, you build classes from smaller classes; rather than using inheritance or duplicating object structures. How this would look like in your case obviously depends on your needs, but I imagine that you wish to copy that ITag data to another class that has more properties:
public class SomeObject
{
// Members:
public string Name { get; set; }
public string Description { get; set; }
// Members to copy from ITag
public int Id { get; set; }
public int ApplicationId { get; set; }
public string Value { get; set; }
// more members
}
Instead, you can compose SomeObject from a concrete Tag DTO:
public class SomeObject
{
// Members:
public string Name { get; set; }
public string Description { get; set; }
public Tag Tag { get; set; }
// more members
}
This way you don't have to copy Tag's members; you only have to set the Tag property with a reference to the deserialized Tag DTO.
This question already has answers here:
Deserialize json with known and unknown fields
(5 answers)
Closed 6 years ago.
I'm doing some web API integration with Newtonsoft.Json, and as always, I have to do dumb stunts to properly deserialize what they're sending back.
In this case, the API will send responses resembling this kind of structure:
{ "contacts": [ ... ], "has-more": true, "offset": 38817 }
The "has-more" and "offset" properties are pretty much constant on the different method responses, and have been defined accordingly on the response object that I'm deserializing into. The response object looks something like this:
public class APIResponse {
public JContainer Result { get; set; }
[JsonProperty("has-more")]
public bool HasMore { get; set; }
[JsonProperty("offset")]
public int Offset { get; set; }
}
That first "contacts" property is what can vary; for some methods, I might get "contacts", some might get "companies", and others might get who-knows-what. I also don't have any way to be certain that every response will have such a "variable" property, nor that it will be the first one, positionally speaking.
For this example, what I would like to happen is the deserializer looks at the Json and says, "Let's see, I don't see anything mapping to 'contacts', so we'll put that into 'Result', and then I can see from the JsonProperty attributes that 'has-more' and 'offset' go into HasMore and Offset. Okay, all set, here's your object."
I suspect this involves some tricks with a custom JsonConverter or IContractResolver, but I'm just not connecting the dots here. I tried doing a simple custom contract resolver, but it appears to use contract resolvers to resolve object property names into property names to look for in the JSON text, not vice-versa.
You can use a base class + derivations for each response type.
public class APIResponseBase {
[JsonProperty("has-more")]
public bool HasMore { get; set; }
[JsonProperty("offset")]
public int Offset { get; set; }
}
public class ContactsResponse : APIResponseBase {
public IEnumerable<Contact> Contacts { get; set; }
}
public class CompaniesResponse : APIResponseBase {
public IEnumerable<Company> Companies { get; set; }
}
var contactsResponse = JsonConvert.Deserialize<ContactsResponse>(json);
IEnumerable<Contact> contacts = contactsResponse.Contacts
Suppose I have a model:
public class Menu
{
public string Name { get; set; }
public IMenuCommand Next { get; set; }
}
IMenuCommand could have different implementations, like:
public class NextStepCommand : IMenuCommand
{
public int Step { get; set; }
}
public class VoiceCommand : IMenuCommand
{
public string Message { get; set; }
}
And I want to POST menus with different commands to the ASP.NET Web API service. How can I do that?
The request below will create an object with specified Name, but Next command will be null:
POST http://localhost/api/menus: {"name":"bob","next":{"step":1}}
Returns 201: {"Name":"bob","Next":null}
Default Web API binders can't map my request params to the needed C# type - of course it's a tricky part. Can I use some "known-type" attribute for interface-based properties or is there any other approach to handle this case, probably a custom model binder?
I think what you're looking for is Json.NET's support for type name handling. It allows you to specify the type to deserialize into by adding the "$type" json tag. You can try this code out to see how it works:
Console.WriteLine(JsonConvert.DeserializeObject<Menu>(
#"{
""name"":""bob"",
""next"":
{
""$type"" : ""ConsoleApplication.NextStepCommand,ConsoleApplication"",
""step"" : 1
}
}",
new JsonSerializerSettings() { TypeNameHandling = TypeNameHandling.Auto }).Next);
You'll have to replace the namespace and assembly name with your own, but you should see the NextStepCommand being correctly deserialized.
In WebAPI, you'll need to tweak your request to add the "$type" type information, and you'll need to enable TypeNameHandling like this:
config.Formatters.JsonFormatter.SerializerSettings.TypeNameHandling = TypeNameHandling.Auto;