Error response when trying to send JSON body using HttpRequestMessage - c#

I need to send body parameters using JSON. I'm working with Printify APIs.
I keep getting error response from server, that my body parameters are empty.
This is the command I'm trying to create:
POST https://api.printify.com/v1/uploads/images.json
it needs to includes the body parameters (that's an example from the API guide):
BODY PARAMETER (UPLOAD IMAGE BY BASE64-ENCODED CONTENTS)
{
"file_name": "image.png",
"contents": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg=="
}
This is my code:
public class ImageContentsParams
{
public string FileName { get; set; }
public string Contents { get; set; }
}
ImageContentsParams imageContents = new ImageContentsParams();
imageContents.FileName = "example.png";
byte[] imageArray = System.IO.File.ReadAllBytes("D:\\example.png");
imageContents.Contents = Convert.ToBase64String(imageArray);
var json = JsonConvert.SerializeObject(imageContents);
using (HttpClient client = new HttpClient())
{
var request = new HttpRequestMessage(new HttpMethod("POST"), "https://api.printify.com/v1/uploads/images.json");
request.Content = jsonBody;
using (HttpResponseMessage res = await client.SendAsync(request))
{
// here I'm checking the returned response
}
}
I keep getting the following error response from Prinify server (this is after parsing):
Code: 10100
Message: Validation failed.
Reason:
file_name: The file name field is required.
contents: The contents field is required when url is not present.
url: The url field is required when contents is not present.
What am I doing wrong???

FileName property will be serialized into fileName and that will not match file_name convention. Change the property to match or specify mapping schema on the serialization to translate FileName into file_name.
You can do the mapping by specifyng [JsonProperty("file_name")] attribute on the FileName property. Something like this:
public class ImageContentsParams
{
[JsonProperty("file_name")]
public string FileName { get; set; }
public string Contents { get; set; }
}

Probably your FileName in JsonContentParams must be renamed to be the same as the JSON that is expected in that service. This is because the params will be serialized and will not match with the specification of the service.
public class ImageContentsParams
{
public string file_name { get; set; }
public string contents { get; set; }
}
Another solution can be to add the JsonProperty attribute, in order to not to refactor all your code.
public class ImageContentsParams
{
[JsonProperty("file_name")]
public string FileName { get; set; }
[JsonProperty("contents")]
public string Contents { get; set; }
}
Try something like that and tell me if it works.

Related

System.NotSupportedException: ... API HTTPPost with .net and c#

I am an engineering student, doing my final degree project based on xamarin apps, including a connection between the client (xamarin) and API (.net). I am trying to send some encrypted data (in base64 encoding) included on a json object as the Request. On the side of the API, it takes the json request, does some fully homomorphic encryption functions and returns the response within new encrypted information.
The problem is when I am trying to receive the response in API as a self-created class named "Post.cs" which includes the next properties;
public class Post
{
public ulong ? userId { get; set; }
public int ? id { get; set; }
public string? title { get; set; }
public string? body { get; set; }
public string? userIdEncrypted { get; set; }
public string? userIdEncryptedReturned { get; set; }
public string? parmsStr { get; set; }
public Post(ulong? userId, int? id, string? title, string? body, string? userIdEncrypted, string? userIdEncryptedReturned, string? parmsStr)
{
this.userId = userId;
this.id = id;
this.title = title;
this.body = body;
this.userIdEncrypted = userIdEncrypted;
this.userIdEncryptedReturned = userIdEncryptedReturned;
this.parmsStr = parmsStr;
}
So, my API takes the request and deserialize it in order to create a "Post" and do some stuff with it.
I am trying to reproduce HttpPost as follows:
[Route("api/[controller]")]
[ApiController]
public class PostController
{
#region CONSTRUCTOR
public PostController()
{
}
#endregion
//POST ://api/Post
[Route("api/[controller]")]
[HttpPost]
public Post ReceivePost([FromBody] Post post)
{
...
var _post = new Post(post.userId, post.id, post.title, post.body, post.userIdEncrypted
post.userIdEncryptedReturned, post.parmsStr);
... FHE functions...
return _post;
}
}
So, at the time I post the "Post" from the client on xamarin, I am sending a Post as the already mentioned structure, where userIdEncrypted and parmsStr contains a base64 encoded string. When it arrives to the API server, the following issue appears:
Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware[1]
An unhandled exception has occurred while executing the request.
System.NotSupportedException: Deserialization of types without a parameterless constructor, a singular parameterized constructor, or a parameterized constructor annotated with 'JsonConstructorAttribute' is not supported. Type 'System.IO.Stream'. Path: $ | LineNumber: 0 | BytePositionInLine: 1.
---> System.NotSupportedException: Deserialization of types without a parameterless constructor, a singular parameterized constructor, or a parameterized constructor annotated with 'JsonConstructorAttribute' is not supported. Type 'System.IO.Stream'.
--- End of inner exception stack trace ---
CLIENT ON XAMARIN APP
This is the json string that I post from the client:
PostModel postAux = new PostModel()
{
userId = 2,
id = 1,
title = "Title for post 1",
body = "Body for post 1",
};
/******************************************************
* Encrypt data of the post (userId)
******************************************************/
PostModel newPost = initializeFHE(postAux);
//Here is where I fill the encrypted data (base64 string) included in the Post object
/******************************************************
* POST encrypted data to the server in csharp
******************************************************/
Uri requestUri = new Uri("http://myHost:3000/api/Post");
var client = new HttpClient();
client.DefaultRequestHeaders
.Accept
.Add(new MediaTypeWithQualityHeaderValue("application/json")); // ACCEPT header
var json = JsonConvert.SerializeObject(newPost);
var contentJson = new StringContent(json.ToString(), Encoding.UTF8, "application/json");
//Console.WriteLine(contentJson);
var response = await client.PostAsync(requestUri, contentJson);
...
In which PostModel refers to this self-created Model:
public class PostModel : BaseViewModel
{
public ulong userId { get; set; }
public int id { get; set; }
public string title { get; set; }
public string body { get; set; }
public string userIdEncrypted { get; set; }
public string userIdEncryptedReturned { get; set; }
public string parmsStr { get; set; }
}
I am aware of my inexperience programming on .Net and c#, so any help and explanations are welcome.
Regards,
Raul.
this is one of those rare error messages that tells you exactly what the problem is
Deserialization of types without a parameterless constructor, a singular parameterized constructor, or a parameterized constructor annotated with 'JsonConstructorAttribute' is not supported.
you need to add a default constructor to Post
public Post() {}

Parsing JSON from API - C#

I am requesting a JSON from a standard web service and I need to handle the response so I can work with the objects. I am working in Xamarin Studio - not that i think that matters.
You can see a result from web service by:
https://dawa.aws.dk/vejnavne/autocomplete?q=due
This is requesting street names in Denmark with 'due' in it.
public async Task doAsyncAddress(string input)
{
var template = "https://dawa.aws.dk/vejnavne/autocomplete?q={0}";
var url = string.Format(template, input);
using (var httpClient = new HttpClient())
{
try
{
Task<HttpResponseMessage> getResponse = httpClient.GetAsync(url);
HttpResponseMessage response = await getResponse;
var responseJsonString = await response.Content.ReadAsStringAsync();
/*
I have tried different things here, with with JsonConvert and JObject but neither works.. I have an idea that the son string is in wrong format, with "\n" included and i have tried to remove these, but still without results. I can see the string so I know it is there.. But it is not formatted correctly.
*/
}
catch (Exception ex)
{
string message = ex.Message;
return message;
}
}
}
With the JsonConverter.DeserializeObject i do this:
var adress = JsonConvert.DeserializeObject<List<Address>>(responseJsonString);
where Address:
public class Address
{
public string tekst { get; set; }
public List<Vejnavne> vejnavn
{ get; set; }
}
public class Vejnavne
{
public string href { get; set; }
public string navn { get; set; }
}
and the response is:
"Cannot deserialize the current JSON object (e.g.
{\"name\":\"value\"}) into type
'System.Collections.Generic.List`1[MinEjendom.Vejnavne]' because the
type requires a JSON array (e.g. [1,2,3]) to deserialize
correctly.\nTo fix this error either change the JSON to a JSON array
(e.g. [1,2,3]) or change the deserialized type so that it is a normal
.NET type (e.g. not a primitive type like integer, not a collection
type like an array or List) that can be deserialized from a JSON
object. JsonObjectAttribute can also be added to the type to force it
to deserialize frenter code hereom a JSON object.\nPath
'[0].vejnavn.href', line 5, position 11.”
And with JObject i get:
"Error reading JObject from JsonReader. Current JsonReader item is not
an object: StartArray. Path '', line 1, position 1."
Your C# code is wrong. This is the correct one:
public class Vejnavn
{
public string href { get; set; }
public string navn { get; set; } // not List<Vejnavne> vejnavn
}
public class Address
{
public string tekst { get; set; }
public Vejnavn vejnavn { get; set; }
}
Then call it like this:
var adress = JsonConvert.DeserializeObject<List<Address>>(responseJsonString);
When you've JSON, you are .NET developer and finally - you have to convert JSON to C# class, you should use Edit - > Paste Special -> Paste JSON as classes. This is an awesome tool :)
Your code is wrong. This is the generated class from your JSON :
public class Class1
{
public string tekst { get; set; }
public Vejnavn vejnavn { get; set; }
}
public class Vejnavn
{
public string href { get; set; }
public string navn { get; set; }
}
When you have successfully generated your code, you can rename the class.

The header of response web service in c#

The format of response
adbc91a43e988a3b5b745b8529a90b61
<RESPONSE Stamp="YYYY-MM-DDTHH:MM:SSZ" RE="…" ERR_TEXT="…">
<PaymentID>3242343</PaymentID>
</RESPONSE>
The first line of the response consists of a md5-hash xml-response + parameters hash, followed by
xml-response.
The main element of xml-response is called RESPONSE...
How and where to add the hash code?
Thanks
I have XML without hashcode. My code in c#
[WebMethod]
public RESPONSE GET( string id)
{
RESPONSE res = new RESPONSE();
res.ERR_TEXT = "";
res.RE = "";
res.Stamp = DateTime.Now.ToString("yyyy-MM-ddthh-mm-ssz");
res.PaymentID = id;
return res;
}
public class RESPONSE
{
[XmlAttribute]
public string ERR_TEXT { get; set; }
[XmlAttribute]
public string RE { get; set; }
[XmlAttribute]
public string Stamp { get; set; }
public string PaymentID { get; set; }
}
In output get only XML. But must still pass the hash code.
I must send a response to a client request. And they want that at response body was hash and xml. And how it should look like I can not understand.

Parse a Json String to create a new custom object c#

I am returning a json string to a WebMethod in WebForms and I want to take the json string and parse it into custom Order objects.
I have a class:
public class Order
{
public string Item { get; set; }
public string Color { get; set; }
public string Qty { get; set; }
public string Size { get; set; }
}
And a WebMethod:
[WebMethod]
public static string SendOrder(string json)
{
List<Order> orders = new List<Order>();
return json;
}
I am passing this string:
{
json: [
{
"Item":"Nike Polo #286772 - Women's Dri-FIT Micro Pique Short Sleeved Polo",
"Size":"XL",
"Color":"Light Blue",
"Quantity":"3"
},
{
"Item":"Port Authority Women's Jacket #L790 - Black",
"Size":"Medium",
"Color":"Black",
"Quantity":"3"
}
]
}
I want to loop through this string and creating new Orders.
What is the best way to do this?
That JSON is a little oddly formatted as it maps to the following classes (using http://json2csharp.com):
public class Json
{
public string Item { get; set; }
public string Size { get; set; }
public string Color { get; set; }
public string Quantity { get; set; }
}
public class RootObject
{
public List<Json> json { get; set; }
}
I'm not sure why you have a top-level variable named json, but whatever.
At this point just use JSON.NET to deserialize into the structure.
JsonConvert.DeserializeObject<RootObject>(yourJsonString);
If you want to rename the object from Json to Order you'll need to use an attribute for that. I don't recall the name off the top of my head but it should be easy to find in the JSON.NET documentation.
I recently completed a Windows Phone app that retrieved info from a Web API-based server as Json strings. I ended up using the JsonConvert class to convert my lists of objects from Json strings to my custom objects. Here's an example of one of my client-side methods that receives and converts the Json strings:
public async void GetGames()
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("base url");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = await client.GetAsync("specific url extention (like api/Order)");
if (response.IsSuccessStatusCode)
{
string s = await response.Content.ReadAsStringAsync();
var deserializedResponse = JsonConvert.DeserializeObject<List<Order>>(s);
//rest of code
}
}
}
Also, make sure that your web method is actually doing something. The example web method you posted creates creates a new list then just returns the parameter you passed in. Using Web API, you could return a list of all Order objects in your database via a method similar to the following:
public IQueryable<Order> GetOrders()
{
return db.Orders; //db is an instance of your DbContext class
}
I hope this is helpful. Let me know if you have any questions.

HttpClient ObjectContent JSON: format with root class name in json object?

I generate a C# class for a json source using json2csharp.com. My json is:
{
"email_verified": true,
"user_id": "gg2323",
"app_metadata": {
"tc_app_user": {
"user_guid": "c0fb150f6er344df98ea3a06114e1e4a",
"cto_admin_a_user_id": "551294d4f6cfb46e65a5aq71",
"lang": "EN",
"country": "USA",
"disabled": false
}
and my resulting C# is:
public class TcAppUser
{
public string user_guid { get; set; }
public string cto_admin_a_user_id { get; set; }
public string lang { get; set; }
public string country { get; set; }
public bool disabled { get; set; }
}
public class AppMetadata
{
public TcAppUser tc_app_user { get; set; }
public int logins_count { get; set; }
}
public class RootObject
{
public bool email_verified { get; set; }
public string user_id { get; set; }
public AppMetadata app_metadata { get; set; }
}
Using the .NET HttpClient GET, I can read into this C# structure from the JSON API quite nicely. Going the other way (POST, PATCH) poses a problem: my app_metadata property name is dropped in the generated JSON output when I use a common approach like:
//Would be nice: var contentIn = new ObjectContent<string>(RootObjectInstance.app_metadata, new JsonMediaTypeFormatter());
string json = JsonConvert.SerializeObject(RootObjectInstance.app_metadata);
HttpResponseMessage response = await hclient.PatchAsync("api/users/" + user_id, new StringContent(json, Encoding.UTF8, "application/json"));
The resulting JSON is now:
{
"tc_app_user": {
"lang": "en-en",
"country": "GER",
"disabled": false
}
}
My quick hack is to use the following additional wrapper to dynamically repackage the app_metadata property so it has the same format going out that it had coming in. The rest remains the same as above:
dynamic wireFormatFix = new ExpandoObject();
wireFormatFix.app_metadata = usr.app_metadata;
string json = JsonConvert.SerializeObject(wireFormatFix);
Now my JSON output corresponds to the JSON input. My question: what is best-practice to achieve symmetric json input and output here without a pesky format fix?
EDIT: If I try to PATCH the entire structure (RootObjectInstance instead of RootObjecInstance.app_metadata) I get:
{
"statusCode": 400,
"error": "Bad Request",
"message": "Payload validation error: 'Additional properties not allowed: 'user_id'."
}
So, I must either send the app_metadata subset/property of the C# RootObject, properly packaged, or I must selectively delete fields from the RootObject to meet the API's requirements.
Thanks!
The root app_metadata tag is being removed from your JSON because you're simply not serializing it. This:
string json = JsonConvert.SerializeObject(RootObjectInstance.app_metadata);
Will serialize everything that is inside app_metadata.
If you serialized the entire object graph, you wouldn't need to patch anything:
string json = JsonConvert.SerializeObject(RootObjectInstance);
As a side note, you should follow C# naming conventions. You can use JsonProperty to help you with that.
Edit:
Ok, after your edit i see the actual problem. You're calling an API by user_id in your query string, and you also have a user_id property inside your object. This seems like you need two different objects for the job.
You have a couple of possibilities:
Create an object hierarchy:
public class BaseObject
{
[JsonProperty(email_verified)]
public bool EmailVerified { get; set; }
[JsonProperty(app_metadata)]
public AppMetadata AppMetadata { get; set; }
}
public class ExtendedObject : BaseObject
{
[JsonProperty(user_id)]
public string UserId { get; set; }
}
And then use the base type to serialize the data:
var baseObj = new BaseObject(); // Fill the object properties.
var json = JsonConvert.SerializeObject(intermidiateObj);
HttpResponseMessage response = await hclient.PatchAsync("api/users/" +
user_id,
new StringContent(json,
Encoding.UTF8,
"application/json"));
Use an anonymous object which includes only properties you actually need:
var intermidiateObj = new { app_metadata = usr.app_metadata };
var json = JsonConvert.SerializeObject(intermidiateObj);
HttpResponseMessage response = await hclient.PatchAsync("api/users/" +
user_id,
new StringContent(json,
Encoding.UTF8,
"application/json"));

Categories