如何设置 WCF 自定义反序列化错误消息 [英] How set a WCF custom deserialization error message

查看:37
本文介绍了如何设置 WCF 自定义反序列化错误消息的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在创建一个 WCf 网络服务,我想知道如果枚举 DataMember 的反序列化失败是否可以设置自定义错误消息?

我有一个这样的枚举

 [数据契约]公共枚举 VehicleBrand{[枚举成员]宝马 = 0,[枚举成员]本田 = 1,[枚举成员]特斯拉 = 2}

还有我的数据契约:

 [数据契约]公开课 MyCar{[DataMember(IsRequired = true, Order = 1)][必需(ErrorMessage =需要汽车品牌.")][EnumDataType(typeof(VehicleBrand), ErrorMessage =需要汽车品牌.")]public VehicleBrand CarBrand { get;放;}}

例如,如果有人通过 SoapUI 调用我的网络服务并将Mercedes"作为 CarBrand 的值,他会收到一些错误消息,指出无法反序列化 CarBrand...是否可以自定义此错误消息,例如CarBrand 应该是 BMW、Honda 或特斯拉?

我正在使用 DevTrends.WCFDataAnnotations.ValidateDataAnnotationsBehavior 来验证 WCF 的 DataContracts.

谢谢

解决方案

您可以使用

以上代码引用自此

I'm creating a WCf webservice and I wonder if it's possible to set an custom error message if deserialization of a an enum DataMember fail?

I have an enum like this

    [DataContract]
    public enum VehicleBrand
    {
        [EnumMember]
        BMW = 0,
        [EnumMember]
        Honda = 1,
        [EnumMember]
        Tesla = 2
    }

And my DataContract:

    [DataContract]
    public class MyCar
    {
        [DataMember(IsRequired = true, Order = 1)]
        [Required(ErrorMessage = "Car brand is required.")]
        [EnumDataType(typeof(VehicleBrand), ErrorMessage = "Car brand is required.")]
        public VehicleBrand CarBrand { get; set; }
    }

If for example someone calls my webservice through SoapUI and put "Mercedes" as a value for the CarBrand, he will get some error message saying that it's not possible to deserialize CarBrand... Is it possible to customize this error message to say for example that the "CarBrand should be BMW, Honda or Tesla"?

I'm using using DevTrends.WCFDataAnnotations.ValidateDataAnnotationsBehavior to validate DataContracts for WCF.

Thanks

解决方案

You can use an IErrorHandler to accomplish that:

Client.cs:

  class Program
    {
        [DataContract]
        public enum MyDCServer
        {
            [EnumMember]
            Test = 0
        }
        [ServiceContract]
        public interface ITestServer
        {
            [OperationContract]
           [FaultContract(typeof(string))]
            MyDCServer EchoDC(MyDCServer input);
        }
        static Binding GetBinding()
        {
            BasicHttpBinding result = new BasicHttpBinding();
            return result;
        }
        static void Main(string[] args)
        {
            string baseAddress = "http://localhost:8000/Service";
            ChannelFactory<ITestServer> factory = new ChannelFactory<ITestServer>(GetBinding(), new EndpointAddress(baseAddress));
            ITestServer proxy = factory.CreateChannel();
            MyDCServer uu = proxy.EchoDC(MyDCServer.Test);
            Console.WriteLine(uu);
            Console.ReadKey();
        }
    }

The value transmitted by the client is Test.

Server.cs:

 public class Post
    {
        [DataContract]
        public enum MyDCServer
        {
            [EnumMember]
            BMW = 0,
            [EnumMember]
            Honda = 1,
            [EnumMember]
            Tesla = 2
        }
        [ServiceContract]
        public interface ITestServer
        {
            [OperationContract]
           [FaultContract(typeof(string), Action = Service.FaultAction)]
            MyDCServer EchoDC(MyDCServer input);
        }
     
        public class Service : ITestServer
        {
            public const string FaultAction = "http://my.fault/serializationError";
            public MyDCServer EchoDC(MyDCServer input)
            {
                Console.WriteLine(input);

                return input;
            }
        }
        public class MyErrorHandler : IErrorHandler
        {
            public bool HandleError(Exception error)
            {
                return error is FaultException && (error.InnerException as SerializationException != null);
            }

            public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
            {
                if (error is FaultException)
                {
                    SerializationException serException = error.InnerException as SerializationException;
                    if (serException != null)
                    {
                        string detail = String.Format("{0}: {1}", serException.GetType().FullName, serException.Message);
                        FaultException<string> faultException = new FaultException<string>(detail, new FaultReason("CarBrand should be BMW, Honda or Tesla"));
                        MessageFault messageFault = faultException.CreateMessageFault();
                        fault = Message.CreateMessage(version, messageFault, Service.FaultAction);
                    }
                }
            }
        }
        public class MyServiceBehavior : IServiceBehavior
        {
            public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
            {
            }
            public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
            {
                foreach (ChannelDispatcher disp in serviceHostBase.ChannelDispatchers)
                {
                    disp.ErrorHandlers.Add(new MyErrorHandler());
                }
            }
            public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
            {
                foreach (ServiceEndpoint endpoint in serviceDescription.Endpoints)
                {
                    if (endpoint.Contract.ContractType == typeof(IMetadataExchange)) continue;
                    foreach (OperationDescription operation in endpoint.Contract.Operations)
                    {
                        FaultDescription expectedFault = operation.Faults.Find(Service.FaultAction);
                        if (expectedFault == null || expectedFault.DetailType != typeof(string))
                        {
                            throw new InvalidOperationException("Operation must have FaultContract(typeof(string))");
                        }
                    }
                }
            }
        }
        static Binding GetBinding()
        {
            BasicHttpBinding result = new BasicHttpBinding();
            return result;
        }
        static void Main(string[] args)
        {
            string baseAddress = "http://localhost:8000/Service";
            ServiceHost host = new ServiceHost(typeof(Service), new Uri(baseAddress));
            host.AddServiceEndpoint(typeof(ITestServer), GetBinding(), "");
            host.Description.Behaviors.Add(new MyServiceBehavior());
            host.Open();
            Console.WriteLine("Host opened");
            Console.ReadLine();
            host.Close();
        }
    }

And there is no Test in the enumeration type of the server.

When the client calls, it will get the following exception information:

The code above is referenced from this link;

UPDATE:

We can use serException.TargetSite.Name to determine whether an enumeration type serialization exception has occurred:

if (serException != null&& serException.TargetSite.Name== "ReadEnumValue")
                        {
                            string detail = String.Format("{0}: {1}", serException.GetType().FullName, serException.Message);
                            FaultException<string> faultException = new FaultException<string>(detail, new FaultReason("CarBrand should be BMW, Honda or Tesla"));
                            MessageFault messageFault = faultException.CreateMessageFault();
                            fault = Message.CreateMessage(version, messageFault, Service.FaultAction);
                        }

For how to apply MyServiceBehavior in the configuration file, you can refer to this link.

You can also use Attribute to apply MyServiceBehavior to the service:

public class MyServiceBehavior : Attribute,IServiceBehavior
            {...

这篇关于如何设置 WCF 自定义反序列化错误消息的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆