繁体   English   中英

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

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

我在Winforms或WPF上托管的Tcp Wcf Service中遇到错误。 服务挂起或引发“线程退出”错误。

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

谢谢。

服务器:

  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 

描述,DateTime? senddate){Symbol = symbol; 系列=系列; AskPrice = Askprice; BidPrice =竞标价格; LTP = ltp; 体积=体积; 说明=说明; 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(); } } } 

在winforms / wpf应用程序中,服务器和客户端之间的通信应在仅负责此任务的辅助线程上进行。 如果将您具有的操作放在按钮btnSubscribe_Click上的新线程中,则应用程序将正常运行。

查看有关如何在wpf中使用线程的更多详细信息:

c#wpf运行按钮单击新线程

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

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