ASMX to WCF SOAP Headers
Hi,
I've written a large asmx web service and now i want to port it to WCF service. What is the easiest way to do that by having in mind that i have applied [SoapHeader] attribute to almost every web method in the asmx service. This attribute always points to one SoapHeader inheritor class. Can I add some attribute ( like SoapHeaderAttribute in asmx ) along with the OperationContractAttribute to add this SOAP header. Or I have to create a wrapper classes for all types I use in order to add the header by using MeassgeHeader.
Thanks in advance,
Kostadin
Answers
As you say, you could use the [MessageContract] model and use [MessageHeader] to do this. Another possibility is to just programmatically add and find headers, as in the sample code below. I have bolded the parts where the client adds a header to the outbound message and the server reads it off the inbound message.
using System;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
using System.ServiceModel.Channels;[ServiceContract]
public interface IMyContract
{
[OperationContract]
string echo(string s);
}public class MyService : IMyContract
{
public string echo(string s)
{
// fyi, here is what the wire message looked like
Console.WriteLine(OperationContext.Current.RequestContext.RequestMessage.ToString());
// find the header we are interested in (lookup by name/namespace)
int index = OperationContext.Current.IncomingMessageHeaders.FindHeader("foo", "");
string h = OperationContext.Current.IncomingMessageHeaders.GetHeader<string>(index);
Console.WriteLine(h);return s;
}
}public class Repro
{
public static void Main()
{
Uri address = new Uri("http://localhost:8004/Service");
Binding binding = new BasicHttpBinding();ServiceHost service = new ServiceHost(typeof(MyService), address);
service.AddServiceEndpoint(typeof(IMyContract), binding, address);
service.Open();ChannelFactory<IMyContract> cf = new ChannelFactory<IMyContract>(binding, new EndpointAddress(address));
IMyContract proxy = cf.CreateChannel();
using (OperationContextScope ocs = new OperationContextScope((IContextChannel)proxy))
{
// add header with name "foo", namespace "", value "val" to this operation call
OperationContext.Current.OutgoingMessageHeaders.Add(MessageHeader.CreateHeader("foo", "", "val"));
Console.WriteLine(proxy.echo("Hello World"));
}
((IClientChannel)proxy).Close();
service.Close();
Console.WriteLine("Done, press a key");
Console.ReadKey();
}
}
All Replies
As you say, you could use the [MessageContract] model and use [MessageHeader] to do this. Another possibility is to just programmatically add and find headers, as in the sample code below. I have bolded the parts where the client adds a header to the outbound message and the server reads it off the inbound message.
using System;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
using System.ServiceModel.Channels;[ServiceContract]
public interface IMyContract
{
[OperationContract]
string echo(string s);
}public class MyService : IMyContract
{
public string echo(string s)
{
// fyi, here is what the wire message looked like
Console.WriteLine(OperationContext.Current.RequestContext.RequestMessage.ToString());
// find the header we are interested in (lookup by name/namespace)
int index = OperationContext.Current.IncomingMessageHeaders.FindHeader("foo", "");
string h = OperationContext.Current.IncomingMessageHeaders.GetHeader<string>(index);
Console.WriteLine(h);return s;
}
}public class Repro
{
public static void Main()
{
Uri address = new Uri("http://localhost:8004/Service");
Binding binding = new BasicHttpBinding();ServiceHost service = new ServiceHost(typeof(MyService), address);
service.AddServiceEndpoint(typeof(IMyContract), binding, address);
service.Open();ChannelFactory<IMyContract> cf = new ChannelFactory<IMyContract>(binding, new EndpointAddress(address));
IMyContract proxy = cf.CreateChannel();
using (OperationContextScope ocs = new OperationContextScope((IContextChannel)proxy))
{
// add header with name "foo", namespace "", value "val" to this operation call
OperationContext.Current.OutgoingMessageHeaders.Add(MessageHeader.CreateHeader("foo", "", "val"));
Console.WriteLine(proxy.echo("Hello World"));
}
((IClientChannel)proxy).Close();
service.Close();
Console.WriteLine("Done, press a key");
Console.ReadKey();
}
}Thanks Brian,
This solution is fine, but I wish that the soap header which has always the same structure for all messages to be described in the WSDL for all this messages. Is [MessageContract] the only solution for that scenario and can I somehow add [MessageHeader] to the method so it won't be necessary to create new MessgaeContract types for all methods.
So if I have this:
[
OperationContract]ReturnType methodOne( type1 param1, type2 param2, ..... , typeN paramN )
Can i add some attribute to
this signature to tell that the incomming ant outgoing messages are decorated with some header - "MySoapHeader"Or I have to
do the following:[
OperationContract]OutgoingMessage methodOne( IncommingMessage incommingMessage )
[MessageContract]
public
class IncommingMessage{
[
MessageHeader]MySoapHeader mySoapHeader;
[
MessageBodyMember]type1 param1;
.....
[
MessageBodyMember]typeN paramN;
}
[
MessageContract]public
class OutgoingMessage{
[
MessageHeader]MySoapHeader mySoapHeader;
[
MessageBodyMember]ReturnType returnParam;
}
There is one problem with the MessageContract approach. There are asp.net clients using the service I am porting to WCF one. And these clients must remain unchanged when consuming the new WCF service. But when returning a MessageContract ( header + method return value ) from a method the asp.net clients generate proxy method returning void ( not the actual return type specified in the MessageContract ) and having the retrurn value as out parameter + one more out parameter of type bool starting with the same name as the first one and ending with "Specified".
So instead of generating the proper one:
returnType methodOne( ... )
it generates something like:
void methdOne( out returnType returnValue, out bool returnValueSpecified, ... )
Is there any way to make it generate the first one?
Thanks
- Try this:
...
[MessageContract (IsWrapped = false)]
public class OutgoingMessage
{
[MessageHeader]
MySoapHeader mySoapHeader;
[MessageBodyMember]
ReturnType returnParam;
}
...
Bye
Marco - This might help:
http://www.codeplex.com/WCFExtras


