WCF Service fault handling WS-Discovery Resolve message

1.9k views Asked by At

We have a WCF service that implements discovery. It's working fine but we have an error handler that seems to be catching a message on the network at the moment that I'm not sure is invalid or not. After using a network monitor it seems to be handling/ignoring other discovery-related messages just not this one.

My question: Is there some kind of extra configuration I can add to my service to elegantly handle this (type of) message?

I just wondered if we're missing anything. If there is not simple solution I'm happy to let our service handle it as a fault as it is currently.

Here's the fault:

System.ServiceModel.FaultException: The message with To '' cannot be processed at the receiver, due to an AddressFilter mismatch at the EndpointDispatcher. Check that the sender and receiver's EndpointAddresses agree. at System.ServiceModel.Dispatcher.ErrorBehavior.ThrowAndCatch(Exception e, Message message) Soap12 (http://www.w3.org/2003/05/soap-envelope) Addressing10 (http://www.w3.org/2005/08/addressing) HandleError: System.InvalidOperationException: The supplied message cannot be sent because the destination is unknown. This transport requires that either Message.Headers.To or Message.Properties.Via be set to a valid value on the outgoing message. at System.ServiceModel.Channels.ServerUdpOutputChannel.GetSendSockets(Message message, IPEndPoint& remoteEndPoint, Exception& exceptionToBeThrown
 at System.ServiceModel.Channels.UdpOutputChannel.SendAsyncResult.Initialize(Message message
 at System.ServiceModel.Channels.UdpOutputChannel.SendAsyncResult..ctor(UdpOutputChannel channel, Message message, TimeSpan timeout, AsyncCallback callback, Object state
 at System.ServiceModel.Channels.UdpOutputChannel.OnBeginSend(Message message, TimeSpan timeout, AsyncCallback callback, Object state
 at System.ServiceModel.Channels.OutputChannel.BeginSend(Message message, TimeSpan timeout, AsyncCallback callback, Object state
 at System.ServiceModel.Dispatcher.DuplexChannelBinder.DuplexRequestContext.OnBeginReply(Message message, TimeSpan timeout, AsyncCallback callback, Object state
 at System.ServiceModel.Channels.RequestContextBase.BeginReply(Message message, TimeSpan timeout, AsyncCallback callback, Object state
 at System.ServiceModel.Channels.RequestContextBase.BeginReply(Message message, AsyncCallback callback, Object state
 at System.ServiceModel.Dispatcher.ChannelHandler.ProvideFaultAndReplyFailure(RequestContext request, Exception exception, ErrorHandlerFaultInfo& faultInfo, Boolean& replied, Boolean& replySentAsync) HandleError: System.ServiceModel.FaultException: The message with To '' cannot be processed at the receiver, due to an AddressFilter mismatch at the EndpointDispatcher. Check that the sender and receiver's EndpointAddresses agree. at System.ServiceModel.Dispatcher.ErrorBehavior.ThrowAndCatch(Exception e, Message message) ProvideFault: System.ServiceModel.FaultException: The message with To '' cannot be processed at the receiver, due to an AddressFilter mismatch at the EndpointDispatcher. Check that the sender and receiver's EndpointAddresses agree. at System.ServiceModel.Dispatcher.ErrorBehavior.ThrowAndCatch(Exception e, Message message) Soap12 (http://www.w3.org/2003/05/soap-envelope) Addressing10 (http://www.w3.org/2005/08/addressing) HandleError: System.InvalidOperationException: The supplied message cannot be sent because the destination is unknown. This transport requires that either Message.Headers.To or Message.Properties.Via be set to a valid value on the outgoing message. at System.ServiceModel.Channels.ServerUdpOutputChannel.GetSendSockets(Message message, IPEndPoint& remoteEndPoint, Exception& exceptionToBeThrown
 at System.ServiceModel.Channels.UdpOutputChannel.SendAsyncResult.Initialize(Message message
 at System.ServiceModel.Channels.UdpOutputChannel.SendAsyncResult..ctor(UdpOutputChannel channel, Message message, TimeSpan timeout, AsyncCallback callback, Object state
 at System.ServiceModel.Channels.UdpOutputChannel.OnBeginSend(Message message, TimeSpan timeout, AsyncCallback callback, Object state
 at System.ServiceModel.Channels.OutputChannel.BeginSend(Message message, TimeSpan timeout, AsyncCallback callback, Object state
 at System.ServiceModel.Dispatcher.DuplexChannelBinder.DuplexRequestContext.OnBeginReply(Message message, TimeSpan timeout, AsyncCallback callback, Object state
 at System.ServiceModel.Channels.RequestContextBase.BeginReply(Message message, TimeSpan timeout, AsyncCallback callback, Object state
 at System.ServiceModel.Channels.RequestContextBase.BeginReply(Message message, AsyncCallback callback, Object state
 at System.ServiceModel.Dispatcher.ChannelHandler.ProvideFaultAndReplyFailure(RequestContext request, Exception exception, ErrorHandlerFaultInfo& faultInfo, Boolean& replied, Boolean& replySentAsync) HandleError: System.ServiceModel.FaultException: The message with To '' cannot be processed at the receiver, due to an AddressFilter mismatch at the EndpointDispatcher. Check that the sender and receiver's EndpointAddresses agree. at System.ServiceModel.Dispatcher.ErrorBehavior.ThrowAndCatch(Exception e, Message message)

Here's the message:

<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:wsd="http://schemas.xmlsoap.org/ws/2005/04/discovery"><soap:Header><wsa:To>urn:schemas-xmlsoap-org:ws:2005:04:discovery</wsa:To><wsa:Action>http://schemas.xmlsoap.org/ws/2005/04/discovery/Resolve</wsa:Action><wsa:MessageID>urn:uuid:2729e487-0e96-42e9-a3fb-96c32c6193de</wsa:MessageID></soap:Header><soap:Body><wsd:Resolve><wsa:EndpointReference><wsa:Address>urn:uuid:1c852a4d-b800-1f08-abcd-2c59e5c16898</wsa:Address></wsa:EndpointReference></wsd:Resolve></soap:Body></soap:Envelope>

And here is my sample app that's based on the default WCF new project template:

Program.cs:

using System;
using System.Diagnostics;
using System.Net;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.Discovery;
using System.ServiceModel.Dispatcher;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                Uri baseAddress = new Uri(String.Format("net.tcp://{0}:8004/Service", Dns.Resolve(Dns.GetHostName()).HostName));
                ServiceHost serviceHost = new ServiceHost(typeof(Service1), baseAddress);

                // Setup the binding and open the WCF service
                NetTcpBinding binding = new NetTcpBinding(SecurityMode.None);
                OptionalReliableSession reliableSession = binding.ReliableSession;
                reliableSession.Enabled = false;
                reliableSession.InactivityTimeout = TimeSpan.MaxValue;
                binding.ReceiveTimeout = TimeSpan.MaxValue;
                binding.MaxBufferSize = 1000000000;
                binding.MaxReceivedMessageSize = 1000000000;
                binding.MaxBufferPoolSize = 524288;
                binding.TransferMode = TransferMode.Buffered;
                binding.ReaderQuotas.MaxStringContentLength = int.MaxValue;
                binding.ReaderQuotas.MaxArrayLength = int.MaxValue;
                binding.ReaderQuotas.MaxBytesPerRead = int.MaxValue;

                ServiceEndpoint serveEnd = serviceHost.AddServiceEndpoint(typeof(IService1), binding, String.Empty);

                ServiceDiscoveryBehavior serviceDiscoveryBehavior = new ServiceDiscoveryBehavior();
                serviceHost.Description.Behaviors.Add(serviceDiscoveryBehavior);

                UdpDiscoveryEndpoint discEnd = new UdpDiscoveryEndpoint();
                serviceHost.AddServiceEndpoint(discEnd);

                serviceHost.Open();

                Console.WriteLine(baseAddress);
                Debug.WriteLine(baseAddress);

                Console.Read();
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex);
                //throw;
            }
        }
    }
}

IService1.cs and Service1.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;

namespace ConsoleApplication1
{
    // NOTE: You can use the "Rename" command on the "Refactor" menu to change the interface name "IService1" in both code and config file together.
    [ServiceContract]
    public interface IService1
    {
        [OperationContract]
        string GetData(int value);

        [OperationContract]
        CompositeType GetDataUsingDataContract(CompositeType composite);

        // TODO: Add your service operations here
    }

    // Use a data contract as illustrated in the sample below to add composite types to service operations.
    [DataContract]
    public class CompositeType
    {
        bool boolValue = true;
        string stringValue = "Hello ";

        [DataMember]
        public bool BoolValue
        {
            get { return boolValue; }
            set { boolValue = value; }
        }

        [DataMember]
        public string StringValue
        {
            get { return stringValue; }
            set { stringValue = value; }
        }
    }
}


using System;
using System.Diagnostics;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;

namespace ConsoleApplication1
{
    // NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "Service1" in both code and config file together.
    public class Service1 : IService1, IErrorHandler, IServiceBehavior
    {
        public string GetData(int value)
        {
            return string.Format("You entered: {0}", value);
        }

        public CompositeType GetDataUsingDataContract(CompositeType composite)
        {
            if (composite == null)
            {
                throw new ArgumentNullException("composite");
            }
            if (composite.BoolValue)
            {
                composite.StringValue += "Suffix";
            }
            return composite;
        }

        public bool HandleError(Exception error)
        {
            Debug.WriteLine("HandleError: {0}", error);
            Console.WriteLine("HandleError: {0}", error);

            return false;
        }

        public void ProvideFault(Exception error, System.ServiceModel.Channels.MessageVersion version, ref System.ServiceModel.Channels.Message fault)
        {
            Debug.WriteLine("ProvideFault: {0} {1}", error, version);
            Console.WriteLine("ProvideFault: {0} {1}", error, version);
        }

        #region IServiceBehavior Members

        public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
        {
            return;
        }

        public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
        {
            foreach (ChannelDispatcher channelDispatcher in serviceHostBase.ChannelDispatchers)
            {
                channelDispatcher.ErrorHandlers.Add(this);
            }
        }

        public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
        {
            return;
        }

        #endregion


    }
}

Cheers, Chris.

2

There are 2 answers

0
ZZZ On BEST ANSWER

I encountered the same problem: Things work, but the discovery endpoint keep sending message out to nowhere, around every 5 minutes, causing 2 exceptions, as shown in the trace message.

I managed to find out the pre-configured endpoint has contract name TargetService and address urn:docs-oasis-open-org:ws-dd:ns:discovery:2009:01. And I hand googled around and found no threads mentioning this.

I tend to believe this is a defect in this WCF pre-configured endpoint.

I used similar workaround similar to Chris'.

I have a Ping service with its own class and service host, and this class won't be hooked with the error handler, thus won't emit mysterious error messages to the log file. Other business functions go to other classes and another service host, hooked with an error handler to catch uncaught exceptions.

Also, because endpoint discovery is around 200 times slower than direct addressing, I have a wrapper class to buffer the base address found in the first Ping through discovery. And subsequent client calls will be using the address.

1
Jack Ukleja On

You probably don't want to handler errors on system endpoints anyway, so you can use this code to avoid adding a handler except where appropriate:

public class LogUnhandledExceptionBehavior : IServiceBehavior
{
   ...
   public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
    {
        foreach (var channelDispatcher in serviceHostBase.ChannelDispatchers.OfType<ChannelDispatcher>())
        {
            // Don't add error handler on channelDispatcher with system endpoints, as they can throw spurious errors
            // and ones we cannot do anything about anyway.
            if (channelDispatcher.Endpoints.Any(dispatcher => dispatcher.IsSystemEndpoint))
                continue;

            channelDispatcher.ErrorHandlers.Add(GenericErrorHandler.StaticInstance);
        }
    ...
    }