Почему исключения ошибок WCF не сохраняют свои данные после пересечения двух границ? - PullRequest
1 голос
/ 07 июня 2011

Когда исключение ошибки генерируется через границу, может потребоваться параметр типа, чтобы передать подробный объект через границу WCF.Однако я заметил, что когда исключение ошибки пересекает две границы (либо потому, что оно переброшено, либо из-за того, что исключение просто переполняет стек), объект детализации теряется.Это по замыслу?Если да, то почему?

У меня есть хранилище кода, которое показывает это в действии, если вы хотите увидеть, о чем я говорю:

https://bitbucket.org/mckaysalisbury/doublefault/src/

Ответы [ 2 ]

4 голосов
/ 09 июня 2011

Очень интересно, это, безусловно, похоже на ошибку в WCF. Если я переключаю привязку (и адрес) из именованных каналов, чтобы использовать HTTP, это на самом деле работает. Я сообщу об ошибке в команду разработчиков. Спасибо за сообщение об этой проблеме!

Кстати, вот автономный консольный код, который воспроизводит эту проблему.

public class StackOverflow_6267090
{
    static bool useHttp;
    const string baseAddressHttp = "http://localhost:8000/Bug/";
    const string baseAddressPipe = "net.pipe://localhost/Bug/";
    static Binding GetBinding()
    {
        if (useHttp)
        {
            return new BasicHttpBinding();
        }
        else
        {
            return new NetNamedPipeBinding();
        }
    }
    static string GetBaseAddress()
    {
        return useHttp ? baseAddressHttp : baseAddressPipe;
    }
    [ServiceContract]
    public interface IInner
    {
        [OperationContract]
        [FaultContract(typeof(Detail))]
        int DoStuff();
    }
    [ServiceContract]
    public interface IOuter
    {
        [OperationContract]
        [FaultContract(typeof(Detail))]
        int DoStuff();
    }
    [DataContract]
    public class Detail
    {
        [DataMember]
        public string Data { get; set; }

        public override string ToString()
        {
            return string.Format("Detail[Data={0}]", Data);
        }
    }
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
    public class InnerService : IInner
    {
        public int DoStuff()
        {
            //return 3;
            throw new FaultException<Detail>(new Detail { Data = "Something" }, new FaultReason("My special reason"));
        }
    }
    class OuterService : IOuter
    {
        public int DoStuff()
        {
            return Caller.CallInner("In service");
        }
    }
    public static class Caller
    {
        public static int CallInner(string where)
        {
            try
            {
                var factory = new ChannelFactory<IInner>(GetBinding(), new EndpointAddress(GetBaseAddress() + "Inner/"));
                var channel = factory.CreateChannel();
                int result = channel.DoStuff();
                return result;
            }
            catch (FaultException<Detail> e)
            {
                Console.WriteLine("[{0} - CallInner] Error, Message={1}, Detail={2}", where, e.Message, e.Detail);
                throw;
            }
        }

        public static int CallOuter(string where)
        {
            try
            {
                var factory = new ChannelFactory<IOuter>(GetBinding(), new EndpointAddress(GetBaseAddress() + "Outer/"));
                var channel = factory.CreateChannel();
                int result = channel.DoStuff();
                return result;
            }
            catch (FaultException<Detail> e)
            {
                Console.WriteLine("[{0} - CallOuter] Error, Message={1}, Detail={2}", where, e.Message, e.Detail);
                throw;
            }
        }
    }
    public static void TestWith(bool useHttp)
    {
        StackOverflow_6267090.useHttp = useHttp;
        Console.WriteLine("Using address: {0}", GetBaseAddress());
        string baseAddress = GetBaseAddress();
        ServiceHost innerHost = new ServiceHost(typeof(InnerService), new Uri(baseAddress + "Inner/"));
        ServiceHost outerHost = new ServiceHost(typeof(OuterService), new Uri(baseAddress + "Outer/"));
        innerHost.AddServiceEndpoint(typeof(IInner), GetBinding(), "");
        outerHost.AddServiceEndpoint(typeof(IOuter), GetBinding(), "");
        innerHost.Open();
        outerHost.Open();
        Console.WriteLine("Hosts opened");

        Console.WriteLine("Calling inner directly");
        try
        {
            Console.WriteLine(Caller.CallInner("client"));
        }
        catch (FaultException<Detail> e)
        {
            Console.WriteLine("In client, after CallInner, Message = {0}, Detail = {1}", e.Message, e.Detail);
        }

        Console.WriteLine("Calling outer");
        try
        {
            Console.WriteLine(Caller.CallOuter("client"));
        }
        catch (FaultException<Detail> e)
        {
            Console.WriteLine("In client, after CallOuter, Message = {0}, Detail = {1}", e.Message, e.Detail);
        }
        catch (FaultException e)
        {
            Console.WriteLine("BUG BUG - this should not have arrived here. Exception = {0}", e);
        }
    }
    public static void Test()
    {
        TestWith(true);
        Console.WriteLine();
        Console.WriteLine();
        Console.WriteLine();
        TestWith(false);
    }
}
0 голосов
/ 09 июня 2011

Я попробовал ваш пример кода - он работал нормально для меня.Я управлял тремя экземплярами и принимал внутреннее в одном, внешнее в другом, а затем из третьего я назвал внешнее и внутреннее.В обоих случаях я видел подробное сообщение.

...