简体   繁体   English

Winforms或WPF上托管的TCP WCF服务挂起

[英]Tcp wcf service hosted on winforms or wpf hangs

I am getting an error in Tcp Wcf Service hosted on winforms or WPF. 我在Winforms或WPF上托管的Tcp Wcf Service中遇到错误。 The service either hangs or throws "Thread Exited" error. 服务挂起或引发“线程退出”错误。

The same code works fine in a console application. 相同的代码在控制台应用程序中可以正常工作。

Thanks. 谢谢。

Server: 服务器:

  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 

description, DateTime? 描述,DateTime? sentdate) { Symbol = symbol; senddate){Symbol = symbol; Series = series; 系列=系列; AskPrice = askprice; AskPrice = Askprice; BidPrice = bidprice; BidPrice =竞标价格; LTP = ltp; LTP = ltp; Volume = volume; 体积=体积; Description = description; 说明=说明; SentDate = sentdate; SentDate = senddate; } } }}

  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(); } } } 

In the winforms/wpf application the communication between the server and the clients should be done on a secondary thread that is responsible of only that. 在winforms / wpf应用程序中,服务器和客户端之间的通信应在仅负责此任务的辅助线程上进行。 If you put the action that you have on button btnSubscribe_Click in a new thread, the application will run ok. 如果将您具有的操作放在按钮btnSubscribe_Click上的新线程中,则应用程序将正常运行。

See more details of how to work with threads in wpf: 查看有关如何在wpf中使用线程的更多详细信息:

c# wpf run button click on new thread c#wpf运行按钮单击新线程

https://www.c-sharpcorner.com/UploadFile/1c8574/threads-in-wpf/ https://www.c-sharpcorner.com/UploadFile/1c8574/threads-in-wpf/

https://msdn.microsoft.com/en-us/library/ms741870(v=vs.85).aspx https://msdn.microsoft.com/en-us/library/ms741870(v=vs.85).aspx

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM