A data contract that simply takes a string - wcf

Newbie in WCF, I am to define a restful interface for taking in requests in xml. The xml can belongs to any type of schema, instead of defining a data contract describing every data member, I want to my data contract to a simple string, which basicaly says you can send me anything, ideally, it looks below,
[OperationContract]
void SubmitESBMessage(string data);
Tried to define the contract to be
[DataContract]
public class OnRampData
{
[DataMember]
public string Data { get; set; }
}
But I don't want to tell my users to escape their xml and put into the OnRampData.
Anyone please help. Thanks in advance.

If you want to take any XML as your input, then you can use XmlElement or XElement as the parameter type. WCF treats those types as "all the XML from the request body".
[OperationContract]
void SubmitESBMessage(XElement data);

Related

How to serialize complex model to xml format wcf

I am developing a wcf application which is taking c# request model as an input and returning complex response c# model after populating data in it from database. I am using SOAP UI client tool to test my service.
Earlier i had decorated my contract with XmlSerializerFormat attribute and after submitting request i was able to get the response in Result tab of SOAP UI tool. Below is the code snippet of it :
[ServiceContract]
[XmlSerializerFormat]
public interface IService1
{
[OperationContract]
Employee GetData(Employee value);
}
[DataContract]
public class Employee
{
[DataMember]
public int Id { get; set; }
[DataMember]
public string Name { get; set; }
public string Address { get; set; }
}
But now due to some reasons i have removed XmlSerializerFormat attribute from contract and i want default serializer to take care of it. But when i am submitting the request from client , my response model is populating with results but Response tab of SOAP UI shows empty response.
During Response model population when i am removing certain properties from response model, i am able to see result in response tab of SOAP UI tool.
Is Default serializer in facing some issues while serializing some of property of my model. Any other attribute apart from XmlSerializerFormat ?
Please let me know where i am lacking or is there any alternative of XmlSerializerFormat attribute.
Thnx in Advance
Try adding DataContract attribute to the Employee on the class level and DataMember attribute to its properties that you want to be serialized. If it has complex property types of its own they also may need to be decorated similarly. Default serializer in WCF is DataContract serializer FYI.

how to set attributes in soap format WCF

how to set attributes for soap message:
for example my soap messg look like following
<doPaymentResult xmlns:a="http://schemas.datacontract.org/2004/07/MemoService" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<a:errors i:nil="true"/>
<a:messages>
<a:MessageEntity>
<a:codeField>Payment Request Successful</a:codeField>
<a:textField i:nil="true" xmlns:b="http://schemas.microsoft.com/2003/10/Serialization/Arrays"/>
</a:MessageEntity>
</a:messages>
<a:requestTrackCode>20130430T125904R14646</a:requestTrackCode>
<a:status i:nil="true"/>
</doPaymentResult>
</doPaymentResponse>
but i need a soap message which take attributes not elements
like following
<doPaymentResult xmlns:a="http://schemas.datacontract.org/2004/07/MemoService" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<a:errors i:nil="true"/>
<a:messages>
<a:MessageEntity codeField="Payment Request Successful">
some text here
</a:MessageEntity>
</a:messages>
<a:requestTrackCode>20130430T125904R14646</a:requestTrackCode>
<a:status i:nil="true"/>
</doPaymentResult>
</doPaymentResponse>
I am using datacontract in class.
It’s a common problem – you want to return an object from a WCF service as XML, but you either want, or need, to deliver some or all of the property values as XML Attributes instead of XML Elements; but you can’t because the DataContractSerializer doesn’t support attributes (you’re most likely to have seen this StackOverflow QA if you’ve done a web search). Most likely you’ve then migrated all your WCF service code to using the XmlSerializer (with all the XmlElement/XmlAttribute/XmlType attributes et al) – and you’ve cursed loudly.
Well, I’m here to rescue you, because it is possible – and the answer to the problem is actually inferred from the MSDN article entitled ‘Types supported by the Data Contract Serializer’.
The example I’m going to give is purely for illustration purposes only. I don’t have a lot of time, so work with me!
•Create a new Asp.Net WCF service application, you can use Cassini as your web server (probably easier – otherwise you might have to enable Asp.Net compatibility mode).
•Open the web.config and delete the element that was created for the new service.
•The interface and implementation model for this example is overkill. Move the [ServiceContract] and [OperationContract] declarations from the interface that was created for you new service to the class that was also created. Delete the interface.
•Open the .svc markup file and add the following at the end: Factory="System.ServiceModel.Activation.WebServiceHostFactory" – this enables the zero-configuration WCF model for this service (we’re going to create a RESTful service).
•Paste the following class declarations into your svc codebehind:
public interface IExampleData
{
string Description { get; set; }
string Name { get; set; }
int ID { get; set; }
}
public class ExampleData : IExampleData
{
public string Description { get; set; }
public string Name { get; set; }
public int ID { get; set; }
}
public class ExampleDataAttributed : ExampleData, IXmlSerializable
{
#region IXmlSerializable Members
public System.Xml.Schema.XmlSchema GetSchema()
{
return null;
}
public void ReadXml(System.Xml.XmlReader reader)
{
//implement if remote callers are going to pass your object in
}
public void WriteXml(System.Xml.XmlWriter writer)
{
writer.WriteAttributeString("id", ID.ToString());
writer.WriteAttributeString("name", Name);
//we'll keep the description as an element as it could be long.
writer.WriteElementString("description", Description);
}
#endregion
}
Just to demonstrate the point, the class that will be part-serialized to attributes simply derives from one that will be serialized as normal.
•Now add the following two methods to your service class:
[OperationContract]
[WebGet(UriTemplate = "/test1")]
public ExampleData Test1()
{
return new ExampleData() { ID = 1,
Name = "Element-centric",
Description =
"The contents of this item are entirely serialized to elements - as normal" };
}
[OperationContract]
[WebGet(UriTemplate = "/test2")]
public ExampleDataAttributed Test2()
{
return new ExampleData_Attributed() { ID = 2,
Name = "Mixed",
Description =
"Everything except this description will be serialized to attributes" };
}
Cover, and bake for 40 minutes (that is – Build it).
If you left your service as Service1.svc, then run it and open up IE and browse to http://localhost:[port of cassini]/test1
The result should look something like this:
<JSLabs.ExampleData
xmlns="http://schemas.datacontract.org/2004/07/ExampleNamespace"
xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<Description>
The contents of this item are entirely serialized to elements - as normal
</Description>
<ID>
1
</ID>
<Name>
Element-centric
</Name>
</JSLabs.ExampleData>
Now browse to http://localhost:[port of cassini]/test2
<JSLabs.ExampleDataAttributed id="2" name="Mixed"
xmlns="http://schemas.datacontract.org/2004/07/JobServe.Labs.Web">
<description>Everything except this description will be
serialized to attributes</description>
</JSLabs.ExampleDataAttributed>
It’s made a little less impressive by that nasty ‘orrible “xmlns=” attribute that the WCF data contract serializer automatically puts on the type – but, as you can see, the ‘ID’ and ‘Name’ properties have indeed been pushed out as attributes!
We could have made both methods return IExampleData and then used the KnownType attribute on that interface in order to get it to support either (according to what the code of the methods returned).
To support deserializing an object from the attributes, all you have to do is to implement the IXmlSerializable.ReadXml method.
Finally, as the aforementioned MSDN article says about the supported types – you should also be able to use XmlElement/XmlNode types as a way of representing XML directly – the DataContractSerializer, like in this case, take the short route and simply gets the Xml.
This also shouldn’t affect JSON formatting if you’re dual-outputting objects for either XML or JSON clients.
Check the source of this article

Why am I getting an InvalidOperationException after adding a [MessageContract] attribute?

The operation 'PRPA_IN201301UV02' could not be loaded because it has a parameter or return type of type System.ServiceModel.Channels.Message or a type that has MessageContractAttribute and other parameters of different types. When using System.ServiceModel.Channels.Message or types with MessageContractAttribute, the method must not use any other types of parameters.
I'm running a WCF on a console host, this is the contract:
[MessageContract]
public class opRequest
{
[MessageBodyMember]
public string myProperty;
}
[ServiceContract(Namespace = "urn:hl7-org:v3")]
public interface IHL7v3
{
[OperationContract(Name = "PRPA_IN201301UV02", Action = "urn:hl7-org:v3:PRPA_IN201301UV02")]
string PIXManager_PRPA_IN201301UV02(opRequest clientID);
}
It does run when I remove from opRequest class the [MessageContract] and [MessageBodyMember]
I'm completely not sure if that will get me to what I need, so i'll give the wider scope - I'm trying to get the SOAP body to be without an enclosing tag of the parameter name.
for example (the body extract from the SOAP message) instead of:
<s:Body>
<PRPA_IN201301UV02 xmlns="urn:hl7-org:v3">
<clientID>the xml document is enclosed</clientID>
</PRPA_IN201301UV02>
I want it to be like this:
<s:Body>
<PRPA_IN201301UV02 xmlns="urn:hl7-org:v3">
my given xml document will go here...
</PRPA_IN201301UV02>
I need it like that to conform to a standard (HL7v3 PIX Manager SOAP Web Service).
Any ideas?
Looks like you should use MessageContract for your return parameter as well
EDITED:
Have a look at this MSDN article for more details Using Message Contracts
If you design your contract with messages you can't use other types either as a parameter or a return value.
Here is a code snippet from the article:
[OperationContract]
bool Validate(BankingTransaction bt);
// Invalid, the return type is not a message contract.
[OperationContract]
void Reconcile(BankingTransaction bt1, BankingTransaction bt2);
// Invalid, there is more than one parameter.
Did you try to use an XMLDocument as the input parameter instead of opRequest? You will also have to mark the interface to use the XML Serializer:
[ServiceContract(Namespace = "urn:hl7-org:v3")]
[XmlSerializerFormat]
public interface IHL7v3
{
[OperationContract(Name = "PRPA_IN201301UV02", Action = "urn:hl7-org:v3:PRPA_IN201301UV02")]
XMLDocument PIXManager_PRPA_IN201301UV02(XMLDocument doc);
}
I am presuming you are also returning XML.
Please note that this is wide open - any XML can be sent which may not be what you intend as there no explicit data contract.

WCF 4: Passing Empty parameters on a GET request

I'm creating an API which will just use a get request to return some search results from the database, I'm trying to make it so that optional parameters can be passed (easy with WCF) but also so that if parameters are specfied in the query string as long as they are empty they will be ignored by the service.
However if you have the a query string with empty parameters it will return a bad request (400) by the server e.g.
Using a end-user point of your choice pass the following querystring
http://www.exampleservice.com/basic/?apiKey=1234&noOfResults=3&maxSalary=&minSalary=&ouId=0&keywords=Web+Developer
Note that maxSalary and minSalary are not passing values
You then have the following WCF service:
[OperationContract]
[WebGet(UriTemplate = "basic/?apiKey={apiKey}&noOfResults={noOfResults}&maxSalary={maxSalary}&minSalary={minSalary}&ouId={ouId}&keywords={keywords}", BodyStyle = WebMessageBodyStyle.Bare)]
public List<SearchResultsDto> BasicSearch(string keywords, string apiKey, int noOfResults, int maxSalary, int minSalary, int ouId)
{
//Do some service stuff
}
This will cause a 400 error, please can someone explain how you pass empty parameters across to a WCF service or is this just not possible?
Currently passing null or an empty parameter is not supported in WCF, the main solution to this problem is to override the querystringconverter which handles the url as it comes through the pipe but before it reaches the operation contract.
An excellent example of implmenting an extension of the querystringconverter is found here:
In the WCF web programming model, how can one write an operation contract with an array of query string parameters (i.e. with the same name)?
HOWEVER
sadly there is a bug in WCF 4 where you cannot override the querystringconverter, this has been addressed by Microsoft and will be fixed in the SP1 release coming this year.
Until then there is no clean way to deal with this situation other than to handle the exception and return a status code of 400 (bad request) - good documentation of the api should handle this in the interim.
Is it just the integers giving you trouble? Maybe you can try making them nullable?
int? MaxSalary
hope this helps
You could send in "-1", and treat that in your business logic as not sent.
It can be handled in multiple ways. Since you are talking about a REST service that can have optional parameters, my suggestion will be do the something like this.
Create a DataObject that will be accepeted as parameter to this method.
[ServiceContract]
public interface IService1
{
[OperationContract]
[WebGet(RequestFormat=WebMessageFormat.Json)]
RequestObject BasicSearch(RequestObject apiKey);
}
public class Service1 : IService1
{
public RequestObject BasicSearch(RequestObject obj)
{
//Do some service stuff
return obj;
}
}
[DataContract]
public class RequestObject
{
[DataMember]
public string Keywords {get; set;}
[DataMember]
public string ApiKey {get; set;}
[DataMember]
public int NoOfResults { get; set; }
}
Advantages (am going to be short, ping me back for details)
No change in service signature
contract does not change
you will get the flexibility of have
null parameters
you can always extend the number of
parameters without any impact to
existing services
below is the sample input and output from fiddler
note: in the request part i havent passed anything to NumberOfResults intentionally to prove

How do you send complex objects using WCF? Does it work? Is it good?

Can I have a data contract of this shape??
[DataContract]
public class YearlyStatistic{
[DataMember]
public string Year{get;set;}
[DataMember]
public string StatisticName {get;set;}
[DataMember]
public List<MonthlyStatistic> MonthlyStats {get;set}
};
I am assuming here that class MonthlyStatistic will also need to be a DataContract. Can you do this in a web service?
To use the same model for web services, mark your class as Serializable use the XmlRoot and XmlElement in the System.Xml.Serialization namespace. Here is a sample using your example:
[Serializable]
[XmlRoot("YearlyStatistic")]
public class YearlyStatistic
{
[XmlElement("Year")]
public string Year { get; set; }
[XmlElement("StatisticName")]
public string StatisticName { get; set; }
[XmlElement("MonthlyStats")]
public List<MonthlyStatistic> MonthlyStats { get; set; }
}
You will have to do the same thing for your complex object properties of the parent object.
Yep, thats standard WCF serialization right there. Are you trying to say the MonthlyStats collection has a property called WeeklyStats, or that each individual MonthlyStatistic has a WeeklyStat collection? If its the former, that doesnt work in WCF natively. You will have to do some fiddling in order to get it to work. If its the latter, its perfectly fine.
Yes, you can send the data contract you mentioned above back and forth from a WCF service. Like you said, MonthlyStatistic and all its members will have to be defined as data contracts themselves or be built in types (like strings).
You can even send and receive more complex types like when you have a base class but want to send or receive an object of a derived class (you would do that using the KnownType attribute). While receiving (de-serialization), from Javascript, there's a trick using which you have to specify the type for WCF. If you are interested, feel free to ask.