C# 承载在winforms或wpf上的Tcp wcf服务挂起
我在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应用程序中,服务器和客户机之间的通信应该在只负责该通信的辅助线程上完成。如果您在按钮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();
}
}
}