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
Related
I want to remove highlighted node from WEB API request and response.
Below are the class Models used in web api
[DataContract(Namespace = "")]
public class ValidateRequest
{
[DataMember]
public string Client_Code { get; set; }
[DataMember]
public string ClientValidateNo { get; set; }
[DataMember]
public string UserID { get; set; }
[DataMember]
public string Password { get; set; }
}
[DataContract(Namespace = "")]
public class ValidateResponse
{
}
I want to remove highlighted node from WEB API request and response.
Below are the class Models used in web api
To achieve this function, first you need to create a class that inherits from XmlSerializerOutputFormatter:
public class XmlSerializerOutputFormatterNamespace : XmlSerializerOutputFormatter
{
protected override void Serialize(XmlSerializer xmlSerializer, XmlWriter xmlWriter, object value)
{
//applying "empty" namespace will produce no namespaces
var emptyNamespaces = new XmlSerializerNamespaces();
emptyNamespaces.Add("", "any-non-empty-string");
xmlSerializer.Serialize(xmlWriter, value, emptyNamespaces);
}
}
Then, add the following service in ConfigureServices in startup.cs:
services
.AddMvc(options =>
{
options.OutputFormatters.Add(new XmlSerializerOutputFormatterNamespace());
}).AddXmlSerializerFormatters();
In api method:
[Produces("application/xml")]
public IActionResult GetXml(ValidateRequest request)
{
ValidateResponse response = new ValidateResponse()
{
Amount = 100,
ClientValidateNo = request.ClientValidateNo,
Client_Code = request.Client_Code,
DepositorCity = "aaa",
DepositorName = "das",
DepositorState = "sadasd",
Status = "fasfas"
};
return Ok(response);
}
The test result:
I'm currently working on a .NET 4.6 console application. I need to parse a nested XML from an URL and transform the XML into an object list.
The URL for the sample XML is the following:
https://www.w3schools.com/xml/cd_catalog.xml
The XML looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<CATALOG>
<CD>
<TITLE>Empire Burlesque</TITLE>
<ARTIST>Bob Dylan</ARTIST>
<COUNTRY>USA</COUNTRY>
<COMPANY>Columbia</COMPANY>
<PRICE>10.90</PRICE>
<YEAR>1985</YEAR>
</CD>
<CD>
<TITLE>Hide your heart</TITLE>
<ARTIST>Bonnie Tyler</ARTIST>
<COUNTRY>UK</COUNTRY>
<COMPANY>CBS Records</COMPANY>
<PRICE>9.90</PRICE>
<YEAR>1988</YEAR>
</CD>
</CATALOG>
My corresponding C# classes look like this:
[XmlRoot(ElementName = "CATALOG")]
public class Catalog
{
[XmlElement("CD")]
List<Cd> Cds { get; set; }
}
[XmlRoot(ElementName = "CD")]
public class Cd
{
[XmlElement("TITLE")]
public string Title { get; set; }
[XmlElement("ARTIST")]
public string Artist { get; set; }
[XmlElement("COUNTRY")]
public string Country { get; set; }
[XmlElement("COMPANY")]
public string Company { get; set; }
[XmlElement("PRICE")]
public double Price { get; set; }
[XmlElement("YEAR")]
public int Year { get; set; }
}
My program class looks like this:
class Program
{
static void Main(string[] args)
{
Init();
}
public static void Init() {
var url = "https://www.w3schools.com/xml/cd_catalog.xml";
XmlDocument myXmlDocument = new XmlDocument();
myXmlDocument.Load(url);
var catalog = myXmlDocument.InnerXml.ToString();
var result = Deserialize<Catalog>(catalog);
// result is null :(
Console.ReadKey();
}
public static T Deserialize<T>(string xmlText)
{
try
{
var stringReader = new StringReader(xmlText);
var serializer = new XmlSerializer(typeof(T));
return (T)serializer.Deserialize(stringReader);
}
catch (Exception ex)
{
throw;
}
}
}
So far so good, my variable catalog consists out of an XML string, but somehow the XML doesn't get parsed correctly. I always get null as a return result. Perhaps it's because of my class definitions.
What do you think, do you have an idea on how to solve this issue? To retrieve an List<Cd> instead of null.
The error is very subtle. You have done everything right, but you missed to add the public access qualifier in your Catalog class, on the list of Cd like so:
[XmlRoot(ElementName = "CATALOG")]
public class Catalog
{
[XmlElement("CD")]
public List<Cd> Cds { get; set; }
}
Since the access qualifiers default to private, the deserializer is having a hard time finding the correct property to deserialize the XML into.
List<Cd> Cds { get; set; }
Change this line to
Public List<Cd> Cds { get; set; }
I have a Web API built in C# core and I need to customize the XML output that one of my endpoints gives.
To configure my app to return XML and JSON, I use Accept Header like so:
// Add framework services.
services
.AddMvc(options => {
options.RespectBrowserAcceptHeader = true;
})
//support application/xml
.AddXmlDataContractSerializerFormatters()
//support application/json
.AddJsonOptions(options => {
options.SerializerSettings.ContractResolver = new DefaultContractResolver();
});
And I have a model I return on a controller:
public class SageInvoice {
public long Id { get; set; }
public DateTime Created { get; set; }
public long? CustomerId { get; set; }
public long? JobId { get; set; }
public DateTime Date { get; set; }
public decimal Subtotal { get; set; }
public decimal VAT { get; set; }
public decimal Total { get; set; }
}
The XML comes out like so:
<ArrayOfSageInvoice xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/AutomotiveDTO.DTOs.SageIntegration">
<SageInvoice>
<Created>2017-03-15T11:09:34.21</Created>
<CustomerId>1</CustomerId>
<Date>2017-03-15T00:00:00</Date>
<Id>2</Id>
<JobId>1</JobId>
<Subtotal>100.00</Subtotal>
<Total>120.00</Total>
<VAT>20.00</VAT>
</SageInvoice>
<SageInvoice>
<Created>2017-03-15T11:11:26.853</Created>
<CustomerId>2</CustomerId>
<Date>2017-03-15T00:00:00</Date>
<Id>3</Id>
<JobId i:nil="true"/>
<Subtotal>23532.00</Subtotal>
<Total>28238.40</Total>
<VAT>4706.40</VAT>
</SageInvoice>
</ArrayOfSageInvoice>
The consumer of my endpoint doesn't like it structured like this and wants me to make it look more:
<?xmlversion="1.0"encoding="utf-8"?>
<Order>
<OrderSummary>
<OrderID>1</OrderID>
<OrderReference>ORDER1</OrderReference>
<OrderDate>2017-03-15</OrderDate>
<AccountNumber>ACCOUNT1</AccountNumber>
<CompanyName>Company 1</CompanyName>
<ContactTitle>Mr</ContactTitle>
<ContactFirst>Dave</ContactFirst>
<ContactLast>Dave</ContactLast>
<Address1/>
<Address2/>
<Town/>
<County/>
<Postcode/>
<Country/>
<Telephone>01234567890</Telephone>
<NumberOfItems>2</NumberOfItems>
<OrderValue>200</OrderValue>
<Downloaded>false</Downloaded>
</OrderSummary>
<OrderSummary>
...
</OrderSummary>
</Order>
How can I change my XML output to match the above without wrecking the Accept headers JSON + XML input/output functionality?
This should do it (see MSDN). The docs are for .NET Framework, but should also apply to .NET Core.
[CollectionDataContract(Name = "Invoice", ItemName = "InvoiceSummary")]
public class SageInvoice
{
...
}
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?
Here is my problem:
I have this XML file:
<?xml version="1.0" encoding="utf-8" ?>
<settings>
<app name="Application1">
<log name="Log1" path="d:\paths\" filename="Log1File"/>
<log name="Log2" path="d:\paths\"/>
<log name="log3" path="d:\paths\" filename="Log3File"/>
</app>
</settings>
And I'm trying to read it with LINQ and create object of this class:
public class Apps
{
public string Name { get; set; }
public IEnumerable<Logs> Logs { get; set; }
}
public class Logs
{
public string Name { get; set; }
public string Path { get; set; }
public string Filename { get; set; }
}
So far I managed to create this bit of code however looks like it only gets first log element mean time I need all log elements for each app element:
public static IEnumerable<Apps> GetAllApps()
{
var items = from a in db.Descendants("app")
orderby a.Attribute("name").Value
select new Apps
{
Name = a.Attribute("name").Value,
Logs = from b in a.Descendants("log")
select new Logs
{
Name = b.Attribute("name").Value,
Path = b.Attribute("path").Value,
Filename = b.Attribute("filename").Value
}
};
return items;
}
I would use serialization here
XmlSerializer ser = new XmlSerializer(typeof(Settings));
var result = (Settings)ser.Deserialize(stream);
[XmlRoot("settings")]
public class Settings
{
[XmlElement("app")]
public Apps[] apps;
}
public class Apps
{
[XmlAttribute("name")]
public string Name { get; set; }
[XmlElement("log")]
public Logs[] Logs { get; set; }
}
public class Logs
{
[XmlAttribute("name")]
public string Name { get; set; }
[XmlAttribute("path")]
public string Path { get; set; }
[XmlAttribute("filename")]
public string Filename { get; set; }
}
I used fluent API, but let you adapt as you prefer...
Problem is a NullReferenceException, as one of your Logs in xml has no "filename" attribute. And when you use "Value" on a null, you get a NRE.
So, check if the Attribute exists before trying to get it's value.
var it = db.Descendants("app")
.OrderBy(app => app.Attribute("name").Value)
.Select(app => new Apps() {
Name = app.Attribute("name").Value,
Logs = app.Descendants("log").Select(a =>
new Logs() {
Name = a.Attribute("name") != null ? a.Attribute("name").Value : null,
Path = a.Attribute("path") != null ? a.Attribute("path").Value : null,
Filename = a.Attribute("filename") != null ? a.Attribute("filename").Value : null
}).ToList()
}).ToList();