代码之家  ›  专栏  ›  技术社区  ›  Davide Icardi i3arnon

使用IErrorHandler和TCP消息安全性会导致超时

  •  5
  • Davide Icardi i3arnon  · 技术社区  · 14 年前

    下面您可以看到完整的客户端和服务器代码来再现错误。

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.ServiceModel;
    using System.ServiceModel.Description;
    using System.ServiceModel.Dispatcher;
    using System.ServiceModel.Channels;
    
    namespace TestWCFServer
    {
        class Program
        {
            static void Main(string[] args)
            {
                Console.WriteLine("SERVER");
    
                NetTcpBinding binding = new NetTcpBinding();
                binding.Security.Mode = SecurityMode.Message; //If you remove this line the code works!!!!
    
                Uri address = new Uri("net.tcp://localhost:8184/");
    
                // Create the ServiceHost.
                using (ServiceHost host = new ServiceHost(typeof(HelloWorldService)))
                {
                    host.AddServiceEndpoint(typeof(IHelloWorldService), binding, address);
    
                    host.Description.Behaviors.Add(new MyErrorhandlerBehavior());
    
                    host.Open();
    
                    Console.WriteLine("The service is ready at {0}", address);
                    Console.WriteLine("Press  to stop the service.");
                    Console.ReadLine();
    
                    // Close the ServiceHost.
                    host.Close();
                }
            }
        }
    
    
    
        [ServiceContract]
        public interface IHelloWorldService
        {
            [OperationContract]
            string SayHello(string name);
        }
    
        public class HelloWorldService : IHelloWorldService
        {
            public string SayHello(string name)
            {
                if (name == null)
                    throw new ArgumentNullException("name");
    
                return string.Format("Hello, {0}", name);
            }
        }
    
        class MyErrorhandlerBehavior : IServiceBehavior, IErrorHandler
        {
            #region IServiceBahvior
            public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, System.Collections.ObjectModel.Collection endpoints, BindingParameterCollection bindingParameters)
            {
            }
    
            public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
            {
                foreach (ChannelDispatcher chanDisp in serviceHostBase.ChannelDispatchers)
                {
                    chanDisp.ErrorHandlers.Add(this);
                }
            }
    
            public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
            {
            }
            #endregion
    
            #region IErrorHandler Members
            public bool HandleError(Exception error)
            {
                return true;
            }
    
            public void ProvideFault(Exception error,MessageVersion ver, ref Message msg)
            {
                FaultException fe = new FaultException(error.Message);
                MessageFault fault = fe.CreateMessageFault();
                msg = Message.CreateMessage(ver, fault, "net.tcp://localhost:8184/fault");
            }
            #endregion
        }
    }
    

    客户代码:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.ServiceModel;
    using System.ServiceModel.Channels;
    using System.ServiceModel.Description;
    using System.ServiceModel.Dispatcher;
    
    namespace TestWCFClient
    {
        class Program
        {
            static void Main(string[] args)
            {
                Console.WriteLine("CLIENT");
    
                try
                {
                    NetTcpBinding binding = new NetTcpBinding();
                    binding.Security.Mode = SecurityMode.Message; //If you remove this line the code works!!!!
    
                    Uri address = new Uri("net.tcp://localhost:8184/");
                    EndpointAddress endpoint = new EndpointAddress(address);
    
                    HelloWorldServiceClient client = new HelloWorldServiceClient(binding, endpoint);
    
                    Console.WriteLine("Calling client with a valid parameter...");
                    Console.WriteLine(client.SayHello("Davide"));
                    Console.WriteLine("OK");
    
                    Console.WriteLine("Calling client with an invalid parameter...");
                    Console.WriteLine(client.SayHello(null)); //This call causes the timeout when Security is set to Message
                    Console.WriteLine("OK");
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                }
    
    
                Console.WriteLine("Press enter to exit");
                Console.ReadLine();
            }
        }
    
    
        [ServiceContract]
        public interface IHelloWorldService
        {
            [OperationContract]
            string SayHello(string name);
        }
    
        class HelloWorldServiceClient : System.ServiceModel.ClientBase, IHelloWorldService
        {
            public HelloWorldServiceClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress address) :
                base(binding, address)
            { }
    
            public string SayHello(string name)
            {
                return base.Channel.SayHello(name);
            }
        }
    }
    

    binding.Security.Mode = SecurityMode.Message; 在客户机和服务器上,异常被正确地翻译,客户机可以毫无问题地看到它。

    在WCF日志中,我看到以下消息:
    没有为具有“”的消息指定签名消息部分网络.tcp://本地主机:8184/故障“行动。


    如果我使用传输安全性,代码将按预期工作。

    谢谢!

    2 回复  |  直到 14 年前
        1
  •  6
  •   Aliostad    13 年前

    你需要定义 FaultContract OperationContract here

    此外,fault contract对象需要与Action命名空间具有相同的命名空间。

    很痛苦,但终于明白了,现在可以工作了。

        2
  •  4
  •   Davide Icardi i3arnon    14 年前

    在我的例子中,问题出在名称空间中。我已将默认方法替换为:

    public void ProvideFault(Exception error,MessageVersion ver, ref Message     
    {
            FaultException fe = new FaultException(error.Message);
            MessageFault fault = fe.CreateMessageFault();
            msg = Message.CreateMessage(ver, fault, null);
    }
    

    null 参数。