C# 承载在winforms或wpf上的Tcp wcf服务挂起

C# 承载在winforms或wpf上的Tcp wcf服务挂起,c#,wcf,user-interface,tcp,self-hosting,C#,Wcf,User Interface,Tcp,Self Hosting,我在winforms或WPF上托管的Tcp Wcf服务中遇到错误。 服务挂起或抛出“线程已退出”错误 同样的代码在控制台应用程序中也可以正常工作 谢谢 服务器: 在winforms/wpf应用程序中,服务器和客户机之间的通信应该在只负责该通信的辅助线程上完成。如果您在按钮btnSubscribe\u上单击一个新线程,应用程序将正常运行 有关如何在wpf中使用线程的更多详细信息,请参见: 服务挂在哪里?当它挂起时,您可以暂停执行以查找它在哪一行被阻止。您好,Francesco,服务挂起在Sen

我在winforms或WPF上托管的Tcp Wcf服务中遇到错误。 服务挂起或抛出“线程已退出”错误

同样的代码在控制台应用程序中也可以正常工作

谢谢

服务器:


在winforms/wpf应用程序中,服务器和客户机之间的通信应该在只负责该通信的辅助线程上完成。如果您在按钮btnSubscribe\u上单击一个新线程,应用程序将正常运行

有关如何在wpf中使用线程的更多详细信息,请参见:


服务挂在哪里?当它挂起时,您可以暂停执行以查找它在哪一行被阻止。您好,Francesco,服务挂起在SendMessage方法中的pipeProxy.AddMessage(message)行上的客户端。我在那一行设置了一个断点,但是当F10设置时,代码没有转到下一行。所以问题可能出在您的服务的AddMessage方法中。有没有一种方法可以调试它,或者添加服务跟踪?
    namespace WCFService
    {
        //interface declarations just like the client but the callback 
        //decleration is a little different
        [ServiceContract]
        interface IMessageCallback
        {
            [OperationContract(IsOneWay = true)]
            void OnMessageAdded(string message, DateTime timestamp);
        }

        //This is a little different than the client 
        // in that we need to state the SessionMode as required or it will default to "notAllowed"
        [ServiceContract(CallbackContract = typeof(IMessageCallback), SessionMode = SessionMode.Required)]
        public interface IMessage
        {
            [OperationContract]
            void AddMessage(string message);
            [OperationContract]
            bool Subscribe();
            [OperationContract]
            bool Unsubscribe();
        }

        [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
        class RCRServer : IMessage
        {
            private static List<IMessageCallback> subscribers = new List<IMessageCallback>();
            public ServiceHost host = null;


            public void Connect()
            {
                //I'm doing this next part progromatically instead of in app.cfg 
                // because I think it makes it easier to understand (and xml is stupid)
                 host = new ServiceHost(typeof(RCRServer), new Uri("net.tcp://localhost:8000"));

                    //notice the NetTcpBinding?  This allows programs instead of web stuff
                    // to communicate with each other
                    host.AddServiceEndpoint(typeof(IMessage), new NetTcpBinding(), "ISubscribe");

                    try
                    {
                        host.Open();
                        Console.WriteLine("Successfully opened port 8000.");
                        //Console.ReadLine();
                        //host.Close();
                    }
                    catch (Exception e)
                    {
                        Console.WriteLine(e.Message);
                    }

            }



            public bool Subscribe()
            {
                try
                {
                    //Get the hashCode of the connecting app and store it as a connection
                    IMessageCallback callback = OperationContext.Current.GetCallbackChannel<IMessageCallback>();
                    if (!subscribers.Contains(callback))
                        subscribers.Add(callback);
                    return true;
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.Message);
                    return false;
                }
            }

            public bool Unsubscribe()
            {
                try
                {
                    //remove any connection that is leaving
                    IMessageCallback callback = OperationContext.Current.GetCallbackChannel<IMessageCallback>();
                    if (subscribers.Contains(callback))
                        subscribers.Remove(callback);
                    return true;
                }
                catch
                {
                    return false;
                }
            }

            public void AddMessage(String message)
            {

                //Console.WriteLine("Calling OnMessageAdded on callback");

                //foreach (Subscriber s in subscribers.Values.ToList())
                //{ }

                try
                {
                    Console.WriteLine("Clients connected to service " + subscribers.Count.ToString());
                    IMessageCallback callback = OperationContext.Current.GetCallbackChannel<IMessageCallback>();
                    callback.OnMessageAdded(message, DateTime.Now);
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                }

                //Go through the list of connections and call their callback funciton
                //subscribers.ForEach(delegate (IMessageCallback callback)
                //{

                //    //System.Threading.Thread.Sleep(1000);
                //    if (((ICommunicationObject)callback).State == CommunicationState.Opened)
                //    {
                //        Console.WriteLine("Clients connected to service " + subscribers.Count.ToString());
                //        callback.OnMessageAdded(message, DateTime.Now);
                //    }
                //    else
                //    {
                //        subscribers.Remove(callback);
                //    }
                //});

            }
        }
    }


Client:



    namespace WCFClient
    {
        //These are the interface declerations for the client
        [ServiceContract]
        interface IMessageCallback
        {
            //This is the callback interface decleration for the client
            [OperationContract(IsOneWay = true)]
            void OnMessageAdded(string message, DateTime timestamp);
        }


        [ServiceContract(CallbackContract = typeof(IMessageCallback))]
        public interface IMessage
        {
            //these are the interface decleratons for the server.
            [OperationContract]
            void AddMessage(string message);
            [OperationContract]
            bool Subscribe();
            [OperationContract]
            bool Unsubscribe();
        }



        class RCRProxy : IMessageCallback, IDisposable
        {
            IMessage pipeProxy = null;

            //MainWindow mainwindow = new MainWindow();
            //public RCRProxy(MainWindow main)
            //{
            //    mainwindow = main;
            //}
            public bool Connect()
            {
                //note the "DuplexChannelFactory".  This is necessary for Callbacks.
                // A regular "ChannelFactory" won't work with callbacks.
                DuplexChannelFactory<IMessage> pipeFactory =
                      new DuplexChannelFactory<IMessage>(
                          new InstanceContext(this),
                          new NetTcpBinding(),
                          new EndpointAddress("net.tcp://localhost:8000/ISubscribe"));


                try
                {
                    //Open the channel to the server
                    pipeProxy = pipeFactory.CreateChannel();
                    //Now tell the server who is connecting
                    pipeProxy.Subscribe();
                    return true;
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.Message);
                    return false;
                }
            }
            public void Close()
            {
                pipeProxy.Unsubscribe();
            }



            //This function sends a string to the server so that it can broadcast
            // it to all other clients that have called Subscribe().
            public string SendMessage(string message)
            {
                try
                {
                    System.Threading.Thread.Sleep(1000);
                    pipeProxy.AddMessage(message);
                    return "sent >>>>  " + message;
                }
                catch (Exception e)
                {
                    return e.Message;
                }
            }

            //This is the function that the SERVER will call
            public void OnMessageAdded(string message, DateTime timestamp)
            {
                //Console.WriteLine(message + ": " + timestamp.ToString("hh:mm:ss"));
               // mainwindow.txtblkStatus.Text = message + ": " + timestamp.ToString("hh:mm:ss");
            }

            //We need to tell the server that we are leaving
            public void Dispose()
            {
                pipeProxy.Unsubscribe();
            }
        }
    }



    namespace StockTickerClient
    {
        /// <summary>
        /// Interaction logic for MainWindow.xaml
        /// </summary>
        /// 


        public class DataItem
        {
            public string Symbol { get; set; }
            public string Series { get; set; }
            public float? AskPrice { get; set; }
            public float? BidPrice { get; set; }
            public float? LTP { get; set; }
            public int? Volume { get; set; }
            public string Description { get; set; }
            public DateTime? SentDate { get; set; }

            public DataItem(string symbol, string series, float? askprice, float? bidprice, float? ltp, int? volume, string
        public partial class MainWindow : Window
        {

            private void btnSubscribe_Click(object sender, RoutedEventArgs e)
            {
                RCRProxy rp = new RCRProxy();
                if (rp.Connect() == true)
                {

                    // Console.WriteLine("please space to end session");
                    string tmp = "Start";// Console.ReadLine();
                    while (tmp != "Exit")
                    {
                        try
                        {
                            rp.SendMessage(tmp);
                        }
                        catch (Exception ex)
                        {

                            txtblkStatus.Text = ex.Message;
                        }

                        // tmp = Console.ReadLine();
                        // txtblkStatus.Text = rp.SendMessage(tmp);
                    }
                }
                if (((ICommunicationObject)rp).State == CommunicationState.Opened)
                    rp.Close();
            }
        }
    }