I am attempting to work with a REST API using RestSharp and C#.
The documentation for the API that I am using gives a sample XML request:
<?xml version='1.0' encoding='UTF-8'?>
<messages>
<accountreference>EX0000000</accountreference>
<from>07700900654</from>
<message>
<to>07700900123</to>
<type>SMS</type>
<body>Hello Mr Sands.</body>
</message>
<message>
<to>07700900124</to>
<type>SMS</type>
<body>Hello Mr Mayo.</body>
</message>
</messages>
I am struggling to understand how to build the request in the format that they want (multiple elements called "message")
I have created these classes for RestSharp to serialize:
public class messages
{
public string accountreference { get; set; }
public string from { get; set; }
public message message { get; set; }
}
public class message
{
public string to { get; set; }
public string body { get; set; }
}
And here is my RestSharp code:
var client = new RestClient("http://api.url.com/v1.0")
{
Authenticator =
new HttpBasicAuthenticator(
UserName,
Password)
};
var request = new RestRequest("theresource", Method.POST) { RequestFormat = DataFormat.Xml };
request.AddBody(
new messages
{
accountreference = Configuration.AccountReference,
from = Configuration.From,
message =
new message { to = Configuration.Message.To, body = Configuration.Message.Body }
});
var response = client.Execute(request);
This works great when I have only 1 message element, but I don't know how to create multiple message elements without having them nested in an array, which doesn't work with the API.
By default RestSharp is using its own serializer but it also packs the DotNetSerializer so you achieve your goal by changing the serializer like this:
var request = new RestRequest("theresource", Method.POST)
{
RequestFormat = DataFormat.Xml,
XmlSerializer = new RestSharp.Serializers.DotNetXmlSerializer()
};
Then you can use a list of message objects and decorate it with XmlElement attribute:
public class messages
{
public string accountreference { get; set; }
public string from { get; set; }
[XmlElement("message")]
public List<message> messageList { get; set; }
}
public class message
{
public string to { get; set; }
public string body { get; set; }
}
Then you can change the last bit to add multiple messages:
request.AddBody(
new messages
{
accountreference = "ref",
from = "from",
messageList = new List<message>() {
new message { to = "to1", body = "body1" },
new message { to = "to2", body = "body2" }
}
});
which would produce (I got the XML by checking request.Parameters[0].Value):
<?xml version="1.0" encoding="utf-8"?>
<messages>
<accountreference>ref</accountreference>
<from>from</from>
<message>
<to>to1</to>
<body>body1</body>
</message>
<message>
<to>to2</to>
<body>body2</body>
</message>
</messages>
I guess this is the XML format you've been looking for.
Having message as list will work -
public class messages
{
public string accountreference { get; set; }
public string from { get; set; }
public List<message> message { get; set; }
}
public class message
{
public string to { get; set; }
public string body { get; set; }
}
Check the very last answer here -
How to post an array of complex objects with JSON, jQuery to ASP.NET MVC Controller?
If you face issues with list, try this -
Can RestSharp send a List<string> in a POST request?
Related
I am calling SendGrid's Email Activity API using the RestSharp RestClient and it is properly returning data via a standard JSON response.
However, I'd like to deserialize that into a C# object since it would be much easier to work with than a raw JSON string. So I created a C# class that has public properties for each field in the JSON response, and gave them annotations with the exact name of the JSON fields.
But when I call JsonDeserializer().Deserialize>(response), while there's no error/exception, all of the fields in the objects are NULL.
Any ideas what's wrong? (You can just take out the "EventType" references as it's not really relevant here). Relevant code is below.
I'm using RestSharp v106.6.10.0 and Newtonsoft.Json v9.0.0.0 (the latter probably older but that's the library we normally use).
Project is .NET v4.6.1
private void QuerySendGridForEmailActivity(EventType eventType)
{
string query = string.Empty;
RestClient client = null;//new RestClient(emailActivityEndpoint);
RestRequest request = new RestRequest(Method.GET);
request.AddHeader("Authorization", "Bearer " + apiKey);
request.AddParameter("limit", "1000");
if (eventType == EventType.Opens)
{
// request.AddParameter("query", WebUtility.UrlEncode("(Contains(events,\"open\"))"));
client = new RestClient(emailActivityEndpoint + "?limit=10&query=" + System.Web.HttpUtility.UrlPathEncode("(Contains(events,\"open\"))"));
}
IRestResponse response = client.Execute(request);
if (response != null && response.StatusCode == HttpStatusCode.OK)
{
this.emailActivityEvents = new JsonDeserializer().Deserialize<List<EmailActivityEvent>>(response);
int i = 0;
}
else
{
}
}
public class EmailActivityEvent
{
[DeserializeAs(Name = "from_email")]
public string FromEmail { get;set; }
[DeserializeAs(Name = "msg_id")]
public string MessageId { get; set; }
[DeserializeAs(Name = "subject")]
public string Subject { get; set; }
[DeserializeAs(Name = "to_email")]
public string ToEmail { get; set; }
[DeserializeAs(Name = "status")]
public string Status { get; set; }
[DeserializeAs(Name = "opens_count")]
public int OpensCount { get; set; }
[DeserializeAs(Name = "clicks_count")]
public int ClicksCount { get; set; }
[DeserializeAs(Name = "last_event_time")]
public DateTime LastEventTime { get; set; }
}
Ok, I should've gotten this earlier but I didn't think I needed to do this.
I had to add another class that I named "EmailActivity" that just has a List<> of the email events, with a deserialize annotation matching the actual name of the item in JSON. Like this:
public class EmailActivity
{
[DeserializeAs(Name = "messages")]
public List<EmailActivityEvent> Events { get; set; }
}
Then just adjust the deserialize call slightly to this:
var emailActivity = new JsonDeserializer().Deserialize<EmailActivity>(response);
And that did it. Duh.
Just FYI, the JSON being returned was in this format:
{"messages":
[{
"from_email":"from#email.com",
"msg_id":"msgid",
"subject":"Test",
"to_email":"to#email.com",
"status":"delivered",
"opens_count":0,
"clicks_count":0,
"last_event_time":"2019-11-26T20:30:02Z"
},
{
"from_email":"from#email.com",
"msg_id":"msgid",
"subject":"Test",
"to_email":"to#email.com",
"status":"delivered",
"opens_count":0,
"clicks_count":0,
"last_event_time":"2019-11-26T20:30:01Z"
},
{
"from_email":"from#email.com",
"msg_id":"msgid",
"subject":"Test",
"to_email":"to#email.com",
"status":"delivered",
"opens_count":0,
"clicks_count":0,
"last_event_time":"2019-11-25T22:06:25Z"
}
]}
Thanks for your comments!
I'm creating a new Route to my WebApi, which should receive the following XML throught a HTTP POST
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<AcquireKeysRequest>
<version>2</version>
<content>
<id>MTV</id>
<type>VOD</type>
</content>
<protection>
<protection-system>
<type>DASH-CENC</type>
<system-id>urn:mpeg:dash:mp4protection:2011</system-id>
</protection-system>
</protection>
<key-timing>
<position>0</position>
</key-timing>
</AcquireKeysRequest>
I've mapped it through the framework, using the following Model:
public class AcquireKeysRequest
{
public int Version { get; set; }
public Content Content { get; set; }
public Protection Protection { get; set; }
public KeyTiming KeyTiming { get; set; }
}
public class Content
{
public string Id { get; set; }
public string Type { get; set; }
}
public class Protection
{
public ProtecionSystem ProtectionSystem{ get; set; }
}
public class ProtecionSystem
{
public string Type { get; set; }
public string SystemId { get; set; }
}
public class KeyTiming
{
public int Position { get; set; }
}
When I receive the request without the header
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
The mapping works just fine, but when I add the header, it breaks.
How can I ignore it?
[HttpPost]
[Route("{instanceId}")]
public object AcquireKeyRequest([FromUri]int instanceId, AcquireKeysRequest xml)
{
//SomeLogicHere
}
P.S: I know that the names in the Model and in the XML are diferent, I fixed in my code already.
Within your MVC Web API project please add the following package via NuGet:
Microsoft.AspNetCore.Mvc.Formatters.Xml
Then in your startup.cs. Adapt the following to generally enable XML serialization and deserialization.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc(options =>
{
options.Filters.Add(new ProducesAttribute("application/xml"));
}).AddXmlSerializerFormatters();
}
Finally create a Get and Post Method withing a controller and try it out. For me both cases works. With or without the xml-tag.
[HttpGet]
public AcquireKeysRequest Get()
{
AcquireKeysRequest req = new AcquireKeysRequest();
req.KeyTiming = new KeyTiming() { Position = 2 };
req.Protection = new Protection()
{
ProtectionSystem = new ProtecionSystem() {
SystemId = "wkow", Type = "type"
}
};
req.Version = 2;
req.Content = new Content() { Id = "id", Type = "type" };
return req;
}
[HttpPost]
public void Post([FromBody]AcquireKeysRequest value)
{
}
I hope i could help out.
Cheers
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.
I'm new in json and I have a little problem here that I can't solve.
In other json I have {"certificate":"123456789",} and I get the value of that using.
model.cs
class Login //this code is working.
{
[JsonProperty("certificate")]
public string certificate { get; set; }
}
But my problem is when I come up with json dictionary I don't have any Idea how can i get the value from it.
this is my code from controller.cs to get the json from Saba/api/component/location
using(var client = new HttpClient()) //I'm sure this code is working.
{
client.BaseAddress = new Uri(string.Format("https://{0}/", HostUrl));
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Add("SabaCertificate", certificate);
//HTTP GET: /Saba/api/componet/location
HttpResponseMessage response = await client.GetAsync("Saba/api/component/location");
if(response.IsSuccessStatusCode)
{
Location saba = await response.Content.ReadAsAsync<Location>();
//I always get empty location when I try to run the app.
}
}
This is JSON with dictionary.
{
"results": [
{
"loc_name": "Aberdeen - Aberdeen Town Square_489",
"id": "locat000000000001877",
"href": "https://na1.sabacloud.com/Saba/api/component/location/locat000000000001877"
}]
}
How can I get the value of json dictionary?
What I've tried is
Model.cs
[JsonProperty("results")] \\ AggregateException Error
class Location
{
[JsonProperty("loc_name")]
public string loc_name { get; set; }
[JsonProperty("id")]
public string id { get; set; }
[JsonProperty("href")]
public string href { get; set; }
}
But I can't retrieve the value.
Based on the JSON posted in your question you should have something like
public class Result
{
public string loc_name { get; set; }
public string id { get; set; }
public string href { get; set; }
}
public class RootObject
{
public List<Result> results { get; set; }
}
then just call
var rootObject = JsonConvert.DeserializeObject<RootObject>(jsonData);
You can always use JSON Formatter & Validator to test if your JSON is valid, and json2csharp to generate c# classes from json.
Im trying to deserialize this xml response of wcf web service to List using XmlSerializer but it fails with exception message :There is an error in XML document (1, 2)
xml:
<ArrayOfNote xmlns="http://schemas.datacontract.org/2004/07/NotebookService" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<Note>
<Author>Redouane</Author>
<Body>Test note</Body>
<CreationDate>2014-01-28T00:00:00</CreationDate>
<Id>1</Id>
<Title>Hello World</Title>
</Note>
</ArrayOfNote>
c#:
public class Note
{
public int Id { get; set; }
public string Title { get; set; }
public System.DateTime CreationDate { get; set; }
public string Author { get; set; }
public string Body { get; set; }
}
and this is the code i wrote to deserialize the received stream
private HttpClient client = new HttpClient();
private List<Note> notes = new List<Note>();
.
.
.
XmlSerializer serializer = new XmlSerializer(typeof(List<Note>));
var responseData = await response.Content.ReadAsStreamAsync();
List<Note> list = serializer.Deserialize(responseData) as List<Note>;
Please help!
Change the creation of serializer as follows and it should work.
XmlSerializer serializer = new XmlSerializer(typeof(List<Note>),
new XmlRootAttribute("ArrayOfNote") {
Namespace = "http://schemas.datacontract.org/2004/07/NotebookService"
});