I want to create an action that will accept application/xml content.
Basically I have created this so far.
namespace App.Areas.Test.Controllers
{
public class UserModel
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
}
public class TestController : ApiController
{
[HttpPost]
public UserModel Test([FromBody] UserModel um)
{
return um;
}
}
}
When I post the following content
<?xml version="1.0" encoding="UTF-8" ?>
<UserModel>
<FirstName>Some Name</FirstName>
<LastName>Some Last Name</LastName>
<Age>30</Age>
</UserModel>
I end up with this response
<UserModel i:nil="true" />
I tried removing FromBody attribute, but that did not help either. For some reason content is not binding to the existing model.
Did you add the Content-Type : application\xml header? You need to inform the serialiser what format the body is in.
this will do the trick...
var xml = GlobalConfiguration.Configuration.Formatters.XmlFormatter;
xml.UseXmlSerializer = true;
Related
How to properly send array of custom objects to asp.net web api via Postman? What I have done is:
Custom class:
public class SystemConsumerConfiguration
{
public int SystemId { get; }
public Uri CallbackUrl { get; }
public SystemConsumerConfiguration()
{
}
public SystemConsumerConfiguration(int systemId, Uri callbackUrl)
{
SystemId = systemId;
CallbackUrl = callbackUrl;
}
}
View model in REST API:
public class PostDigitalPostSubscriptionConfiguration
{
public IReadOnlyList<SystemConsumerConfiguration> SystemsModel { get; set; }
public IFormFile Certificate { get; set; }
public PostDigitalPostSubscriptionConfiguration()
{
}
}
And now, I make a request in Postman
The problem is, that model is bound with default values:
Forgot to have public setters in SystemConsumerConfiguration.
Should be like this:
public class SystemConsumerConfiguration
{
public int SystemId { get; set; }
public Uri CallbackUrl { get; set; }
public SystemConsumerConfiguration()
{
}
public SystemConsumerConfiguration(int systemId, Uri callbackUrl)
{
SystemId = systemId;
CallbackUrl = callbackUrl;
}
}
Answered in:
Default value in an asp.net mvc view model
I'm trying to exclude a property from my Post Action in a web api controller, is there something like [Bind(Exclude="Property")] for asp.net web api?
This is my model:
public class ItemModel
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
I want to exclude the Id in the Post Action, because it is autogenerated, but I need to return it in my Get Action.
I Know I could have two models, one for my Post action and one for my Get action, but I'm trying to do this with just one model.
I would favour mapping models but this could be achieved by checking if the request is a POST in a ShouldSerialize method:
public class MyModel
{
public string MyProperty1 { get; set; }
public string MyProperty2 { get; set; }
public bool ShouldSerializeMyProperty2()
{
var request = HttpContext.Current.Request;
if (request.RequestType == "POST") return false;
return true;
}
}
Where your method name is the name of the property prefixed with ShouldSerialize.
Note this will work for JSON. For XML, you will need to add the following line to your config:
config.Formatters.XmlFormatter.UseXmlSerializer = true;
You can simply create a DTO for POST.
I have the following ComplexType which I have defined on the PUT action for my controller as follows:
[DataContract(Namespace = "http://schemas.abc.com/formurl", Name = "ComplexData")]
public class ComplexData {
[DataMember] public string Name { get; set; }
[DataMember] public Int32 ID { get; set; }
[DataMember] public DataExchangeList DataExchange { get; set; }
}
[DataContract(Namespace = "http://schemas.abc.com/formurl", Name = "DataItem")]
public class DataItem {
[DataMember] public string Name { get; set; }
[DataMember] public string Value { get; set; }
}
[CollectionDataContract(Namespace = "http://schemas.abc.com/formurl", Name = "DataExchange")]
public class DataExchangeList : List<DataItem> {
}
Here's my controller:
public class ValuesController : ApiController
{
// PUT api/values
public HttpResponseMessage Put(ComplexData data)
{
return Request.CreateResponse<ComplexData>(HttpStatusCode.OK, data);
}
}
When trying to pass the ComplexData type on PUT, the collection DataExchange does not bind properly:
PUT http://localhost:53954/api/values HTTP/1.1
User-Agent: Fiddler
Content-Type: application/x-www-form-urlencoded
Accept: application/xml
Host: localhost:53954
Content-Length: 106
Id=123456789&Name=Complex&DataExchange[0][Name]=Data&DataExchange[0][Value]=ComplexType
The response which simply returns back the data shows the collection is empty:
<ComplexData xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.abc.com/formurl">
<DataExchange />
<ID>123456789</ID>
<Name>Complex</Name>
</ComplexData>
Isn't this supposed to work with the FormUrlEncodedMediaTypeFormatter?
Is there anything wrong with the way I'm passing the Collection data as follows?
DataExchange[0][Name]=Data&DataExchange[0][Value]=ComplexType
Any suggestions would be appreciated.
Thanks,
Sid
I use MS Studio 2010 Express for Windows Phone to build the app. In my app, I got the http respond and read it in string then I deserializer into the class object. It works fine in the class without List collection as a property. When it deserializer the class with List property, it got the error like this
Error in line 12 position 5. Expecting state 'Element'.. Encountered 'EndElement' with name 'ContactList', namespace 'http://schemas.datacontract.org/2004/07/DataObjects’.
I think I can read the xml and assign the value into the class. I searched to read xml file and a lot of website mentions to use XDocument .Prase method or xlmDocument.Load. However event adding the System.Xml.Ling as reference , I still cannot see XDocument .Parse method or xlmDocument . Would someone tell me what I should do in order to assign the following value into the class?
There is my class object:
public class CallDetails
{
public int id { get; set; }
public string summary { get; set; }
public string errorMsg { get; set; }
public int parentCallid { get; set; }
public string parentCallURL { get; set; }
public string assignedTo { get; set; }
public string OrgName { get; set; }
public DateTime onHoldSince { get; set; }
public DateTime onHoldUntil { get; set; }
public string requester { get; set; }
public bool isOnHold { get; set; }
private List<Contact> m_ContactList = new List<Contact>();
public List<Contact> ContactList
{
get { return m_ContactList; }
}
}
There is the respond:
<?xml version="1.0" encoding="utf-8"?><CallDetails xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/DataObjects">
<ContactList>
<Contact>
<Method>PriPhone</Method>
<Number>(604) 555-1234</Number>
</Contact>
<Contact>
<Method>Fax</Method>
<Number>(604)555-1234</Number>
</Contact>
</ContactList>
<errorMsg
i:nil="true" />
<id>0</id>
<isOnHold>false</isOnHold>
<onHoldSince>0001-01-01T00:00:00</onHoldSince>
<onHoldUntil>0001-01-01T00:00:00</onHoldUntil>
<parentCallURL>/Call/349551</parentCallURL>
<parentCallid>0</parentCallid>
<requester>Peter </requester>
<summary>Mobile Application Research</summary>
</CallDetails>
Just adding the reference to System.Xml.Linq won't do it, you also need to reference the namespace in the class header:
using System.Xml.Linq;
Then you can call something like XDocument doc = XDocument.Parse(content);. However, from what I can tell, you are trying to deserialize data, so you might want to use the XmlSerializer class instead for all the core work. You can find some code 'ispiration' here.
I found it that the CallDetail Class cause error. It should be like that
public List<Contact> ContactList { get; set; }
I'm trying out RestSharp for a WP7 project. Having some trouble deserializing some XML with RestSharp. The object is null. Here's some of the relevant XML:
<?xml version="1.0" encoding="utf-8"?>
<api_response xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<response_data>
<employee_information>
<employee>
<employee_sf_name>David</employee_sf_name>
<employee_first_name>Dave</employee_first_name>
<employee_last_name>Jones</employee_last_name>
</employee>
</employee_information>
</response_data>
</api_response>
And here's my request:
public static void executeRequest(Action<string> callback, string method)
{
var client = new RestClient();
var request = new RestRequest(Method.POST);
client.BaseUrl = App.url + method;
request.AddParameter("secret_key", Application.secret_key);
request.AddParameter("email", Application.email);
request.AddParameter("password", Application.password);
client.ExecuteAsync<Employee>(request, response =>
{
callback(response.Content); //prints the response as output
Debug.WriteLine("firstname " + response.Data.employee_first_name);
});
}
And here's the Employee object:
public class Employee
{
public Employee() { }
public int employee_id { get; set; }
public String employee_first_name { get; set; }
public String employee_last_name { get; set; }
}
Since the response comes back fine I tried deserializing it in a separate function, but without success:
public static void parse(string data)
{
Debug.WriteLine(data);
XmlDeserializer xml = new XmlDeserializer();
Employee employee = new Employee();
employee = xml.Deserialize<Employee>(new RestResponse() { Content = data });
Debug.WriteLine("last name " + employee.employee_last_name);
Debug.WriteLine("firstname " + employee.employee_first_name);
}
Thanks in advance if anyone can shed some light on the issue.
First off, the closing tag needs to be a closing tag. After I fixed that, I set up an enclosing class:
public class employee_information
{
public Employee employee { get; set; }
}
Then kept your original Employee class:
public class Employee
{
public Employee() { }
public int employee_id { get; set; }
public String employee_first_name { get; set; }
public String employee_last_name { get; set; }
}
Then, to deserialize it:
var empInfo = xml.Deserialize<employee_information>((new RestResponse() {Content = data}));
Adding request.RootElement = "employee"; should work with your existing code. If you don't want to start that far down the tree, you need to create classes that match the entire hierarchy.