RESTful WCF service that can respond in both JSON(P) and XML and still be used as SOAP web service? - wcf

Given a contract such as:
[ServiceContract] public interface IService
{
[OperationContract]
[WebGet(UriTemplate = "GetData/{id}.{format}")]
ResponseData GetData(string id, string format);
}
Is there a way to get the service to respond with json when requested as:
/GetData/1234.json, xml when requested as /GetData/1234.xml and still be available as a proper soap service at some other url, with a strongly typed wsdl contract?
Using a Stream as the return value for GetData is not workable, as though it fufills the first two requirements, wcf can't create a full wsdl specification as it has no idea what the contents of the resultant Stream will be.

You should have two separate methods which take id and format (and they would call a shared implementation that returns ResponseData) which have different WebGet attributes:
[ServiceContract]
public interface IService
{
[OperationContract]
[WebGet(UriTemplate = "GetData/{id}.{format}.xml",
ResponseFormat=WebMessageFormat.Xml)]
ResponseData GetDataXml(string id, string format);
[OperationContract]
[WebGet(UriTemplate = "GetData/{id}.{format}.json",
ResponseFormat=WebMessageFormat.Json)]
ResponseData GetDataJson(string id, string format);
}
For the SOAP endpoint, you should be able to call either method, but you are going to have to have a separate ServiceHost instance hosting the implementation of the contract.

Related

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.

How to wrap all results of an EndPoint in OperationResult?

I want to wrap each result from one Wcf service in my application in something like
public class OperationResult{
public string Status;
public string Data;
}
even if my contract looks like
[ServiceContract]
internal interface ITest
{
[OperationContract,
WebGet(
RequestFormat = WebMessageFormat.Json,
ResponseFormat = WebMessageFormat.Json)]
MyDc EchoDc(MyDc input);
}
From what I've read the potential extensibility points are IServiceBehavior, IEndpointBehavior, IContractBehavior, IOperationBehavior.
Any thoughts where I can hook my wrapping magic ?
Look # my answer here:
How to customize the process employed by WCF when serializing contract method arguments?
There it is mentioned how you can replace an object of one type to another type while it is being returned.
I think thats not possible via extensionpoints on the WCF framework because what you watn to do is to change your contract.
The contract is a c# interface which is used by your client.
You have to write an own proxy class for use by your client where you can map the operation results to whatever you like:
class ServiceProxy : ClientBase<YourServiceInterface>
{
public OperationResult EchoDc(MyDs input)
{
MyDc result = Channel.EchoDc(input);
return new OperationResult( ... // map your operation result here))
}
}

Send information in Soap Header to WCF service in C#

i want a web application to create a service reference to my WCF service, insert information to the header of the soap call and call my WCF method.
i read about MessageContract attribute and declared one in the interface file:
[MessageContract]
public class BasicServiceHeader
{
[MessageHeader]
public string myString;
}
my WCf interface is:
[ServiceContract]
public interface IBasicService
{
[OperationContract]
[WebGet(UriTemplate = "GetData?value={value}")] // Add support for HTTP GET Requests
string GetData(int value);}
i don't want the BasicServiceHeader to be passed as a parameter of GetData function , i want to keep the function as it is and to extract the BasicServiceHeader inside the function, can i do that ?
Client side, you can pass a header prior invoking the operation:
MessageHeader messageHeader = MessageHeader.CreateHeader(_headerName, _headersNameSpace, _headerValue);
OperationContext.Current.OutgoingMessageHeaders.Add(messageHeader);
and extract it using FindHeader service side

Is it necessary for me to write [OperationContract] over every method in my WCF Service?

For example, is this correct?
[OperationContract]
bool IsHappy(string userID);
bool IsSad(string userID);
bool IsHungry(string userID);
Is that a valid body of operations for a WCF ServiceContract or do I have to do it this way:
[OperationContract]
bool IsHappy(string userID);
[OperationContract]
bool IsSad(string userID);
[OperationContract]
bool IsHungry(string userID);
You must denote every method that you want to expose from the service with [OperationContract]. You are free to have methods without this attribute in your service class but those methods will not be exposed in the service metadata and will not be accessible to the client.
If all three methods are part of the service contract then all three must have an [OperationContract] attribute - your second example is correct.

WCF Additional Proxy Classes

I have a WCF webservice that has the following service contract
[ServiceContract(Namespace = "http://example.org")]
public interface IEquinoxWebservice
{
[OperationContract]
Guid Init();
[OperationContract]
List<Message> Dequeue(Guid instanceId);
[OperationContract]
void Enqueue(Guid instanceId, Message message);
[OperationContract]
void Dispose(string instanceId);
}
Message class is an abstract class that is implemented by a bunch of concrete message classes.
I want to make all the concrete message classes available in the client proxy that is generated. Not just the message class.
Is there any way to make them available as types in the webservice so the standard Visual Studio proxy generator will create them?
You need to specify those types. See Data Contract Known Types.