I'm trying to implement an endpoint behavior which injects a custom SOAP header into all messages to and from a service. I've gotten pretty close by implementing the approach from the accepted answer of this question:
WCF WSDL Soap Header on all operations
After implementing that solution, my custom SOAP header does indeed show up in the WSDL; however, when I try to call the methods on my service, I get the following exception/fault:
<ExceptionDetail xmlns="http://schemas.datacontract.org/2004/07/System.ServiceModel" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<HelpLink i:nil="true" />
<InnerException i:nil="true" />
<Message>Index was outside the bounds of the array.</Message>
<StackTrace> at System.ServiceModel.Dispatcher.DataContractSerializerOperationFormatter.AddHeadersToMessage(Message message, MessageDescription messageDescription, Object[] parameters, Boolean isRequest)
at System.ServiceModel.Dispatcher.OperationFormatter.SerializeReply(MessageVersion messageVersion, Object[] parameters, Object result)
at System.ServiceModel.Dispatcher.DispatchOperationRuntime.SerializeOutputs(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage4(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage3(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage2(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage1(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean isOperationContextSet)</StackTrace>
<Type>System.IndexOutOfRangeException</Type>
</ExceptionDetail>
Looking in Reflector at the DataContractSer开发者_运维知识库ializerOperationFormatter.AddHeadersToMessage method thats throwing the exception, leads me to believe that the following snippet is causing the problem...but I'm not sure why.
MessageHeaderDescription description = (MessageHeaderDescription) headerPart.Description;
object parameterValue = parameters[description.Index];
I think the last line above is throwing the exception. The parameters
variable is from IDispatchFormatter.SerializeReply
What's going on?!?!!
Any help would be greatly appreciated...
I have used the same example ("WCF WSDL Soap Header on all operations"), and the same error ocurred. To solve this error, I removed the header from the request on income, in function "AfterReceiveRequest" in IDispatchMessageInspector. I have modified the example in such a way, that the header is added only to incoming messages.
[DataContract(Name = "AuthHeader", Namespace = "web")]
public class AuthHeader
{
[DataMember(Order = 1)]
public string UserName { get; set; }
[DataMember(Order = 2)]
public string Password { get; set; }
}
public class SoapHeaderEndpointBehavior : BehaviorExtensionElement, IEndpointBehavior
{
#region BehaviorExtensionElement Members
public override Type BehaviorType
{
get
{
return typeof(SoapHeaderEndpointBehavior);
}
}
protected override object CreateBehavior()
{
return new SoapHeaderEndpointBehavior();
}
#endregion
#region IEndpointBehavior Members
public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
{
//throw new NotImplementedException();
}
public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
var inspector = new FvsMessageInspector();
clientRuntime.MessageInspectors.Add(inspector);
}
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
{
var channelDispatcher = endpointDispatcher.ChannelDispatcher;
if (channelDispatcher == null)
return;
foreach (var ed in channelDispatcher.Endpoints)
{
var inspector = new FvsMessageInspector();
ed.DispatchRuntime.MessageInspectors.Add(inspector);
}
foreach (OperationDescription operationDescription in endpoint.Contract.Operations)
{
string nmm = operationDescription.Name;
foreach (MessageDescription msgDescription in operationDescription.Messages)
{
if (msgDescription.Direction == MessageDirection.Input)
{
MessageHeaderDescription header = new MessageHeaderDescription("AuthHeader", "web");
header.Type = typeof(AuthHeader);
msgDescription.Headers.Add(header);
}
}
}
}
public void Validate(ServiceEndpoint endpoint)
{
//throw new NotImplementedException();
}
#endregion
}
public class FvsMessageInspector : IDispatchMessageInspector, IClientMessageInspector
{
#region IDispatchMessageInspector
public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
{
int i = request.Headers.FindHeader("AuthHeader", "web");
if (i >= 0)
{
AuthHeader header = request.Headers.GetHeader<AuthHeader>(i);
//Use header info here
request.Headers.RemoveAt(i);
}
return null;
}
public void BeforeSendReply(ref Message reply, object correlationState)
{
//No need to do anything else
}
#endregion
#region IClientMessageInspector
public object BeforeSendRequest(ref Message request, IClientChannel channel)
{
return null;
}
public void AfterReceiveReply(ref Message reply, object correlationState)
{
//No need to do anything else
}
#endregion
}
But much simpliers aproach is to use WCFExtrasPlus: "https://wcfextrasplus.codeplex.com/wikipage?title=SOAP%20Headers&referringTitle=Documentation"
Instead of modifying the contracts using IServiceBehavior
, I've found that modifying the exported contract using IContractBehavior
and IWsdlExportExtension
works fine and no messages need to be rewritten (like in the other listed answer).
精彩评论