这是服务器代码:
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();
}
}
}
这是客户的:
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
{
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(); 这行常常抛出NullReferenceException,有什么问题?
谢谢!
答案 0 :(得分:3)
您不能只使用回调契约启动WCF服务并立即尝试执行客户端回调。还没有客户。
在您的代码中,我看到您手动实例化MyService
并尝试执行回调方法。这根本行不通。如果要使用GetCallbackChannel
方法,则必须在实际存在通道时进行 - 即在远程WCF客户端调用的实际操作的上下文中。否则,当前没有OperationContext
,您将获得空引用异常,因为OperationContext.Current
会返回null
。
回调旨在用于长时间运行的服务操作。例如:
[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);
}
}
要测试这个,您必须实际创建一个客户端 - 启动一个新项目,添加对此服务的引用,实现导入器生成的回调,使用回调创建InstanceContext
,创建客户端代理使用InstanceContext
,最后调用其PerformLongRunningOperation
方法。
如果您正在尝试开发一个pub / sub实现,其中客户端实际上没有启动操作,只是注册自己接收一些回调,请查看此页面:Using Callback Contracts in WCF for Asynchronous Publish/Subscribe Event-Style Communication。