Sorry for posting the same question again, but kinds didn't get it right the first time. :)
Here's the code of the serv开发者_如何学JAVAer application, that can receive connection and should send messages to the client.
As you can see I have the "class Form1 : Form" for the GUI stuff and "class ServerWCallbackImpl : IServerWithCallback" with the server functions.
The problem is that this classes can not communicate, i.e. I can not induce a server function from a form event, such as buttonClick, nor can I change something within the form, say TextBox1.Text += ... , from the server function.
Maybe someone could please explain, how should the code look like, so that it would work?
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.ServiceModel;
namespace server
{
[ServiceContract(Namespace = "server", CallbackContract = typeof(IDataOutputCallback), SessionMode = SessionMode.Required)]
public interface IServerWithCallback ///// what comes from the client to the server.
{
[OperationContract(IsOneWay = true)]
void StartConnection(string clientName);
[OperationContract(IsOneWay = true)]
void Message_Cleint2Server(string msg);
}
public interface IDataOutputCallback ///// what goes from the sertver, to the client.
{
[OperationContract(IsOneWay = true)]
void AcceptConnection();
[OperationContract(IsOneWay = true)]
void Message_Server2Client(string msg);
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e) /// once the form loads, create and open a new ServiceEndpoint.
{
ServiceHost duplex = new ServiceHost(typeof(ServerWCallbackImpl));
duplex.AddServiceEndpoint(typeof(IServerWithCallback), new NetTcpBinding(), "net.tcp://localhost:9080/service");
duplex.Open();
this.Text = "SERVER *on-line*";
}
private void buttonSendMsg_Click(object sender, EventArgs e)
{
/// callback.Message_Server2Client(textBox2.Text);
/// The name 'Message_Server2Client' does not exist in the current context :(
}
}
class ServerWCallbackImpl : IServerWithCallback /// NEED TO SOMEHOW MERGE THIS ONE WITH THE FORM1 CLASS
{
IDataOutputCallback callback = OperationContext.Current.GetCallbackChannel<IDataOutputCallback>();
public void StartConnection(string name)
{
/// TextBox1.text += name + " has connected!";
/// 'TextBox1' does not exist in the current context :(
/// can't reach form1 components. :/
MessageBox.Show( name + " has connected!");
Message2Client("Welcome, "+name+"!");
}
public void Message_Cleint2Server(string msg)
{
/// TextBox1.text += msg;
/// 'TextBox1' does not exist in the current context :(
/// can't reach form1 components. :/
}
public void Message2Client(string msg)
{
callback.Message_Server2Client(msg);
}
}
}
The lifetime of the duplex variable is limited to the Form1_Load method. That means your host will terminate when the method is finished. To keep the host running declare the duplex variable outside the method and just instantiate it in the method.
Like so:
public partial class Form1 : Form {
//Declare the variable in the class, not the method body
private ServiceHost duplex;
public Form1() {
InitializeComponent();
}
// once the form loads open a new ServiceEndpoint.
private void Form1_Load(object sender, EventArgs e) {
duplex = new ServiceHost(typeof(ServerWCallbackImpl));
duplex.AddServiceEndpoint(typeof(IServerWithCallback), new NetTcpBinding(), "net.tcp://localhost:9080/service");
duplex.Open();
this.Text = "SERVER *on-line*";
}
private void buttonSendMsg_Click(object sender, EventArgs e) {
/// callback.Message_Server2Client(textBox2.Text);
/// The name 'Message_Server2Client' does not exist in the current context :(
}
}
EDIT1:
If ServiceHost is instantiated with a type like in your example an instance of that type will be created for each connection. You can set the lifetime of the instance to session, call or connection I believe. I'm not sure how that object would access your form though. However, if you instantiate the ServerWCallbackImpl class yourself and pass a reference to the host that instance will be used.
public partial class Form1 : Form {
//Declare the variable in the class, not the method body
private ServiceHost duplex;
private ServerWithCallbackImpl localInstance;
public Form1() {
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e) {
localInstance = new ServerWithCallbackImpl();
NetTcpBinding binding = new NetTcpBinding ();
duplex = new ServiceHost(localInstance, new Uri[] { new Uri("net.tcp://localhost:9080") });
duplex .AddServiceEndpoint(typeof(IServerWithCallback), binding, "service");
duplex .Open();
this.Text = "SERVER *on-line*";
}
}
The ServerWithCallbackImpl object will then have to keep track of it's client(s). To have the server update the GUI you might want to pass a reference to the Form as parameter into the ServerWithCallbackImpl constructor. Take a look at the Publish/Subscriber pattern to get a deeper understanding of callbacks.
精彩评论