Here is the server code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.Runtime.Serialization;
using System.ServiceModel.Description;
namespace Console_Chat
{
[ServiceContract(SessionMode = SessionMode.Required, CallbackContract = typeof(IMyCallbackContract))]
public interface IMyService
{
[OperationContract(IsOneWay = true)]
void NewMessageToServer(string msg);
[OperationContract(IsOneWay = false)]
bool ServerIsResponsible();
}
[ServiceContract]
public interface IMyCallbackContract
{
[OperationContract(IsOneWay = true)]
void NewMessageToClient(string msg);
[OperationContract(IsOneWay = true)]
void ClientIsResponsible();
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
public class MyService : IMyService
{
public IMyCallbackContract callback = null;
/*
{
get
{
return OperationContext.Current.GetCallbackChannel<IMyCallbackContract>();
}
}
*/
public MyService()
{
callback = OperationContext.Current.GetCallbackChannel<IMyCallbackContract>();
}
public void NewMessageToServer(string msg)
{
Console.WriteLine(msg);
}
public void NewMessageToClient( string msg)
{
callback.NewMessageToClient(msg);
}
public bool ServerIsResponsible()
{
return true;
}
}
class Server
{
static void Main(string[] args)
{
String msg = "none";
ServiceMetadataBehavior behavior = new
ServiceMetadataBehavior();
ServiceHost serviceHost = new
ServiceHost(
typeof(MyService),
new Uri("http://localhost:8080/"));
serviceHost.Description.Behaviors.Add(behavior);
serviceHost.AddServiceEndpoint(
typeof(IMetadataExchange),
MetadataExchangeBindings.CreateMexHttpBinding(),
"mex");
serviceHost.AddServiceEndpoint(
typeof(IMyService),
new WSDualHttpBinding(),
"ServiceEndpoint"
);
serviceHost.Open();
Console.WriteLine("Server is up and running");
MyService server = new MyService();
server.NewMessageToClient("Hey client!");
/*
do
{
msg = Console.ReadLine();
// callback.NewMessageToClient(msg);
} while (msg != "ex");
*/
Console.ReadLine();
}
}
}
Here is the client's:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.Runtime.Serialization;
using System.ServiceModel.Description;
using Console_Chat_Client.MyHTTPServiceReference;
namespace Console_Chat_Client
{
[ServiceContract(SessionMode = SessionMode.Required, CallbackContract = typeof(IMyCallbackContract))]
public interface IMyService
{
[OperationContract(IsOneWay = true)]
void NewMessageToServer(string msg);
[OperationContract(IsOneWay = false)]
bool ServerIsResponsible();
}
[ServiceContract]
public interface IMyCallbackContract
{
[OperationContract(IsOneWay = true)]
void NewMessageToClient(string msg);
[OperationContract(IsOneWay = true)]
void ClientIsResponsible();
}
public class MyCallback : Console_Chat_Client.MyHTTPServiceReference.IMyServiceCallback
{
static InstanceContext ctx = new InstanceContext(new MyCallback());
static MyServiceClient client = new MyServiceClient(ctx);
public void NewMessageToClient(string msg)
{
Console.WriteLine(msg);
}
public void ClientIsResponsible()
{
}
class Client
开发者_C百科 {
static void Main(string[] args)
{
String msg = "none";
client.NewMessageToServer(String.Format("Hello server!"));
do
{
msg = Console.ReadLine();
if (msg != "ex")
client.NewMessageToServer(msg);
else client.NewMessageToServer(String.Format("Client terminated"));
} while (msg != "ex");
}
}
}
}
callback = OperationContext.Current.GetCallbackChannel(); This line constanly throws a NullReferenceException, what's the problem?
Thanks!
You can't just start a WCF service with a callback contract and immediately try to execute a client callback. There are no clients yet.
In your code, I see you manually instantiating a MyService
and trying to execute a callback method. This simply won't work. If you want to use the GetCallbackChannel
method then it has to be done when there is actually a channel - i.e. in the context of an actual operation invoked by a remote WCF client. Otherwise, there is no current OperationContext
and you'll get a null reference exception because OperationContext.Current
returns null
.
Callbacks are intended to be used with long-running service operations. For example:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
public class MyService : IMyService
{
// One-way method
public void PerformLongRunningOperation()
{
var callback =
OperationContext.Current.GetCallbackChannel<IMyCallbackContract>();
var result = DoLotsOfWork();
callback.LongRunningOperationFinished(result);
}
}
To test this you would have to actually create a client - start a new project, add a reference to this service, implement the callback that the importer generates, create an InstanceContext
with the callback, create the client proxy using that InstanceContext
, and finally invoke its PerformLongRunningOperation
method.
If you are trying to develop a pub/sub implementation, where clients do not actually initiate the operations but simply register themselves to receive some callback, have a look at this page: Using Callback Contracts in WCF for Asynchronous Publish/Subscribe Event-Style Communication.
精彩评论