I have a site that give me this xml response on my GET request:
<ServerUnits>
<State Name="ServerName" Date="2008-04-01" >
<Users>
<User login="someUser1" Password="123456">
<User login="someUser2" Password="qwerty">
</Users>
</ServerUnits>
I want use WCF Client for work with this service.
How to discraibe Message Contract of this response for WCF Clien
It is best to create client proxies for the WCF service. It will create the data contracts for you (as mentioned by #Aliostad) so you don't have to create them manually. To do this right click on your solution and select "Add Service Reference..." from the context-menu and enter the address to your WCF service.
I think that WCF is not useful is your case.
A more simple way would be to write objects that match this xml response and just deserialize xml stream onto objects instances.
What you have posted is not a SOAP message so MessageContract is not appropriate.
I imagine what you posted is the SOAP body content so you need to do something along the line of this:
[DataContract]
public class ServerUnits
{
[DataMember]
public ServerState State { get; set; }
[DataMember]
public List<User> Users { get; set; }
}
[DataContract]
public class ServerState
{
[DataMember]
public string Name { get; set; }
[DataMember]
public DateTime Date { get; set; }
}
[DataContract]
public class User
{
[DataMember]
public string login { get; set; }
[DataMember]
public string password { get; set; }
}
UPDATE
Your message is not SOAP. But you can still use the code above if you use webHttpBinding which sends and receives POX.
Related
I have a .NET Core Web Api which i need to develop to handle a request arriving from another system. The XML i receive has this tag inside:
<root>
<child1>
<child1.1>192.168.1.1</child1.1>
</child1>
<child2>true</child2>
</root>
My Web Api create an endpoint in the Configure Method
app.UseSoapEndpoint<ISampleService>("/Service.svc", new BasicHttpBinding(), SoapSerializer.XmlSerializer);
Finally i have a .NET Core Library where i handle the requests:
public Response Root(Request r)
{
//code
}
Using postman i noticed that my method is called but the Request object is always null.
This is my Request Object
[DataContract]
public class Child1
{
[DataMember]
public string child1.1 { get; set; }
}
public class Request
{
[DataMember]
public Child1 child1 { get; set; }
[DataMember(Name = "child2")]
public string child2 { get; set; }
}
Any ideas?
I am attempting to implement a portion of the Ally Accounts API in C#. I've run into a problem with a particular endpoint.
I want to get a specific account's balance:
[XmlRoot("accountbalance")]
public class SummaryAccountBalance : Balance
{
[XmlElement("buyingpower")]
public BuyingPower BuyingPower { get; set; }
[XmlElement("fedcall")]
public decimal FedCall { get; set; }
[XmlElement("housecall")]
public decimal HouseCall { get; set; }
[XmlElement("money")]
public AccountMoney Money { get; set; }
[XmlElement("securities")]
public Securities Securities { get; set; }
}
Where Balance is a simple abstract class:
public abstract class Balance
{
[XmlElement("account")]
public int Account { get; set; }
[XmlElement("accountvalue")]
public decimal AccountValue { get; set; }
}
For other endpoints this works just fine and I am able to get summary account balance information using this structure, for example in this endpoint.
But the /accounts/xxxxxxx/balances.xml doesn't want to work for me. Given this file:
<?xml version="1.0" encoding="UTF-8"?>
<response id="77cf30da:12df25c7074:-7ea6">
<accountbalance>
<account>12345678</account>
<accountvalue>67119.41</accountvalue>
<buyingpower>
<cashavailableforwithdrawal>66177.48000000001</cashavailableforwithdrawal>
<daytrading>264709.84</daytrading>
<equitypercentage>100</equitypercentage>
<options>66177.48000000001</options>
<soddaytrading>264709.84</soddaytrading>
<sodoptions>66177.48000000001</sodoptions>
<sodstock>132354.96000000002</sodstock>
<stock>132354.96000000002</stock>
</buyingpower>
<fedcall>0.0</fedcall>
<housecall>0.0</housecall>
<money>
<accruedinterest>0.0</accruedinterest>
<cash>66134.67</cash>
<cashavailable>0.0</cashavailable>
<marginbalance>0.0</marginbalance>
<mmf>0.02</mmf>
<total>66134.69</total>
<uncleareddeposits>0.0</uncleareddeposits>
<unsettledfunds>0.0</unsettledfunds>
<yield>0.0</yield>
</money>
<securities>
<longoptions>0.0</longoptions>
<longstocks>57.39</longstocks>
<options>0.0</options>
<shortoptions>0.0</shortoptions>
<shortstocks>0.0</shortstocks>
<stocks>57.39</stocks>
<total>984.72</total>
</securities>
</accountbalance>
</response>
The following code detects it is indeed a SummaryAccountBalance but fails to populate the fields:
var serializer = new XmlSerializer(typeof(SummaryAccountBalance), new XmlRootAttribute("response"));
return (SummaryAccountBalance)serializer.Deserialize(summaryAccountBalance);
where summaryAccountBalance is the byte stream version of the file above.
I'm not sure where I have gone wrong here and I'm pulling my hair out trying to solve it. Even stepping through the code line by line there doesn't seem to be any problems at all until this deserialization step. More to the point, this exact object is used in other endpoints and those endpoint implementations have no problem deserializing it.
What am I missing to make this work?
What am I missing to make this work?
What you are missing is that <response> is not your SummaryAccountBalance. It's the nested <accountbalance> element.
You need to declare one more class to describe the whole XML:
[XmlRoot("response")]
public class SummaryAccountBalanceResponse
{
[XmlAttribute("id")]
public string Id { get; set; }
[XmlElement("accountbalance")]
public SummaryAccountBalance Balance { get; set; }
}
and deserialize into this class:
var serializer = new XmlSerializer(typeof(SummaryAccountBalanceResponse));
return ((SummaryAccountBalanceResponse)serializer.Deserialize(summaryAccountBalance)).Balance;
I've WCF service operation defined in a simple way like
[ServiceContract(Namespace = "http://contoso.com")]
interface ICalculator
{
[OperationContract]
AddResp Add(AddRqst addRequestDummyName);
}
where AddRqst is defined as
[DataContract]
class AddRqst
{
[DataMember]
public decimal A { get; set; }
[DataMember]
public decimal B { get; set; }
}
and the problem I see is that the way WCF serializes and the way it expects requests are wrapped by the parameter name like so (this is from memory)
<Add>
<addRequestDummyName>
<A>1</A>
<B>1.5</B>
</addRequestDummyName>
</Add>
I can't distribute a schema for this file because WCF likes to add and expects that extra wrapper for the parameters. It should look like I designed to be, like so
<Add>
<A>1</A>
<B>1.5</B>
</Add>
I'm aware of MessageContract and I've tested that by changing AddRqst (and also AddResp) to the following removes the wrapping because by using messagecontracts you assume just 1 contract.
[DataContract]
[MessageContract]
class AddRqst
{
[DataMember]
[MessageBodyMember]
public decimal A { get; set; }
[DataMember]
[MessageBodyMember]
public decimal B { get; set; }
}
My question is the following. Is there way to do this just with datacontracts? All my operations have 1 parameter. If not, is the way I modified AddRqst the best way to do this?
If I have a Server/Client application that both reference the same DLL which contains interfaces used for a REST server and for the WebChannelFactory to reference the web server, what would happen to legacy clients if the Servers interface gets and update? For example say version one of an application gets pushed out with the following interface:
[ServiceContract]
public interface ISampleInterface
{
[OperationContract]
[WebInvoke(UriTemplate = "/PutDevice", ResponseFormat = WebMessageFormat.Xml, RequestFormat = WebMessageFormat.Xml)]
void PutDevice(Device device);
}
[DataContract(Namespace = "")]
public class Device
{
[DataMember]
public Guid id { get; set; }
[DataMember]
public string Name { get; set; }
[DataMember]
public string Description { get; set; }
} // End of Device
This is what the REST service uses as a contract and the agent would have code similar to the following:
WebChannelFactory<ISampleInterface> client = new WebChannelFactory<IGridVisionService>(new Uri(targetHost));
ISampleInterface sampleInterface = client.CreateChannel();
sampleInterface.PutDevice(new Device() { id = Guid.Empty(), Name = "Test Device", Description = "Test Device Description" });
So the client application is already deployed to hundreds of computers, but we realize for the version we also want the client to send it's domain so we modify the device data contract to be the following:
[DataContract(Namespace = "")]
public class Device
{
[DataMember]
public Guid id { get; set; }
[DataMember]
public string Name { get; set; }
[DataMember]
public string Domain { get; set; }
[DataMember]
public string Description { get; set; }
} // End of Device
It's easy to update the server, but now there are hunders of agents that do not know about the Domain. What is the proper way to deal with this situation? My only thought was to not use a DataContract but an XElement that I could manually parse. Then add login to the Server for dealing with the case of a missing Domain, but this seems sloppy. Is there a better solution that I am overlooking?
I was able to test this myself. In the case that my Client Device linking to a dll that did not know about the Domain parameter, the method call still succeeded and the Domain parameter was simply null. This is the result I was hoping for!
Assume I have a C# class like this:
[XmlRoot("floors")]
public class FloorCollection
{
[XmlElement("floor")]
public Floor[] Floors { get; set; }
}
And I want to serialize it and send to a REST API using WCF. But before sending I need adding an attribute to the floors node in this way: <floors type="array">...</floors>
Any idea?
Just add the type attribute into your collection class:
[XmlRoot("floors")]
public class FloorCollection
{
[XmlAttribute("type")]
public string Type { get; set; }
[XmlElement("floor")]
public Floor[] Floors { get; set; }
}
If you mean adding that without the business code knowing about it, then you'll probably have to use Message Inspectors to modify the message before it is sent.