.Net Remoting 到 WCF 挑战!
我正在尝试将 .net 远程处理代码迁移到 wcf,但我发现这很困难。 有人可以帮助我将下面这个简单的基于远程处理的程序迁移到使用 WCF 吗? 该程序实现了一个简单的发布者/订阅者模式,其中我们有一个TemperatureProviderProgram,它发布到许多订阅TemperatureProvider的TemperatureSubscriberProgram。
要运行程序:
- 将TemperatureProviderProgram 和TemperatureSubscriberProgram 复制到单独的控制台应用程序项目中。
- 将剩余的类和接口复制到公共类库项目中,然后添加对 System.Runtime.Remoting 库的引用
- 从控制台应用程序项目添加对类库项目的引用。
- 编译并运行1个TemperatureProviderProgram和多个TemperatureSubscriberProgram。
请注意,不应使用 IIS 或 xml。 提前致谢。
public interface ITemperatureProvider
{
void Subcribe(ObjRef temperatureSubcriber);
}
[Serializable]
public sealed class TemperatureProvider : MarshalByRefObject, ITemperatureProvider
{
private readonly List<ITemperatureSubcriber> _temperatureSubcribers = new List<ITemperatureSubcriber>();
private readonly Random randomTemperature = new Random();
public void Subcribe(ObjRef temperatureSubcriber)
{
ITemperatureSubcriber tempSubcriber = (ITemperatureSubcriber)RemotingServices.Unmarshal(temperatureSubcriber);
lock (_temperatureSubcribers)
{
_temperatureSubcribers.Add(tempSubcriber);
}
}
public void Start()
{
Console.WriteLine("TemperatureProvider started...");
BinaryServerFormatterSinkProvider provider = new BinaryServerFormatterSinkProvider();
provider.TypeFilterLevel = System.Runtime.Serialization.Formatters.TypeFilterLevel.Full;
TcpServerChannel tcpChannel = new TcpServerChannel("TemperatureProviderChannel", 5001, provider);
ChannelServices.RegisterChannel(tcpChannel, false);
RemotingServices.Marshal(this, "TemperatureProvider", typeof(ITemperatureProvider));
while (true)
{
double nextTemp = randomTemperature.NextDouble();
lock (_temperatureSubcribers)
{
foreach (var item in _temperatureSubcribers)
{
try
{
item.OnTemperature(nextTemp);
}
catch (SocketException)
{}
catch(RemotingException)
{}
}
}
Thread.Sleep(200);
}
}
}
public interface ITemperatureSubcriber
{
void OnTemperature(double temperature);
}
[Serializable]
public sealed class TemperatureSubcriber : MarshalByRefObject, ITemperatureSubcriber
{
private ObjRef _clientRef;
private readonly Random portGen = new Random();
public void OnTemperature(double temperature)
{
Console.WriteLine(temperature);
}
public override object InitializeLifetimeService()
{
return null;
}
public void Start()
{
BinaryServerFormatterSinkProvider provider = new BinaryServerFormatterSinkProvider();
provider.TypeFilterLevel = System.Runtime.Serialization.Formatters.TypeFilterLevel.Full;
int port = portGen.Next(1, 65535);
TcpServerChannel tcpChannel = new TcpServerChannel(string.Format("TemperatureSubcriber_{0}", Guid.NewGuid()), port, provider);
ChannelServices.RegisterChannel(tcpChannel, false);
ITemperatureProvider p1 = (ITemperatureProvider)RemotingServices.Connect(typeof(ITemperatureProvider), "tcp://localhost:5001/TemperatureProvider");
_clientRef = RemotingServices.Marshal(this, string.Format("TemperatureSubcriber_{0}_{1}.rem", Environment.MachineName, Guid.NewGuid()));
p1.Subcribe(_clientRef);
}
}
public class TemperatureProviderProgram
{
static void Main(string[] args)
{
TemperatureProvider tp = new TemperatureProvider();
tp.Start();
}
}
public class TemperatureSubcriberProgram
{
static void Main(string[] args)
{
Console.WriteLine("Press any key to start TemperatureSubcriber.");
Console.ReadLine();
TemperatureSubcriber ts = new TemperatureSubcriber();
ts.Start();
Console.ReadLine();
}
}
I am trying to migrate my .net remoting code to wcf but I'm finding it difficult. Can someone help me migrate this simple Remoting based program below to use WCF? The program implements a simple publisher/subscriber pattern where we have a single TemperatureProviderProgram that publishers to many TemperatureSubcriberPrograms that subcribe to the TemperatureProvider.
To run the programs:
- Copy the TemperatureProviderProgram and TemperatureSubcriberProgram into seperate console application projects.
- Copying to remaining classes and interfaces into a common Class Library project then add a reference to System.Runtime.Remoting library
- Add a reference to the Class Library project from the console app projects.
- Complie and run 1 TemperatureProviderProgram and multiple TemperatureSubcriberProgram.
Please note no IIS or xml should be used. Thanks in advance.
public interface ITemperatureProvider
{
void Subcribe(ObjRef temperatureSubcriber);
}
[Serializable]
public sealed class TemperatureProvider : MarshalByRefObject, ITemperatureProvider
{
private readonly List<ITemperatureSubcriber> _temperatureSubcribers = new List<ITemperatureSubcriber>();
private readonly Random randomTemperature = new Random();
public void Subcribe(ObjRef temperatureSubcriber)
{
ITemperatureSubcriber tempSubcriber = (ITemperatureSubcriber)RemotingServices.Unmarshal(temperatureSubcriber);
lock (_temperatureSubcribers)
{
_temperatureSubcribers.Add(tempSubcriber);
}
}
public void Start()
{
Console.WriteLine("TemperatureProvider started...");
BinaryServerFormatterSinkProvider provider = new BinaryServerFormatterSinkProvider();
provider.TypeFilterLevel = System.Runtime.Serialization.Formatters.TypeFilterLevel.Full;
TcpServerChannel tcpChannel = new TcpServerChannel("TemperatureProviderChannel", 5001, provider);
ChannelServices.RegisterChannel(tcpChannel, false);
RemotingServices.Marshal(this, "TemperatureProvider", typeof(ITemperatureProvider));
while (true)
{
double nextTemp = randomTemperature.NextDouble();
lock (_temperatureSubcribers)
{
foreach (var item in _temperatureSubcribers)
{
try
{
item.OnTemperature(nextTemp);
}
catch (SocketException)
{}
catch(RemotingException)
{}
}
}
Thread.Sleep(200);
}
}
}
public interface ITemperatureSubcriber
{
void OnTemperature(double temperature);
}
[Serializable]
public sealed class TemperatureSubcriber : MarshalByRefObject, ITemperatureSubcriber
{
private ObjRef _clientRef;
private readonly Random portGen = new Random();
public void OnTemperature(double temperature)
{
Console.WriteLine(temperature);
}
public override object InitializeLifetimeService()
{
return null;
}
public void Start()
{
BinaryServerFormatterSinkProvider provider = new BinaryServerFormatterSinkProvider();
provider.TypeFilterLevel = System.Runtime.Serialization.Formatters.TypeFilterLevel.Full;
int port = portGen.Next(1, 65535);
TcpServerChannel tcpChannel = new TcpServerChannel(string.Format("TemperatureSubcriber_{0}", Guid.NewGuid()), port, provider);
ChannelServices.RegisterChannel(tcpChannel, false);
ITemperatureProvider p1 = (ITemperatureProvider)RemotingServices.Connect(typeof(ITemperatureProvider), "tcp://localhost:5001/TemperatureProvider");
_clientRef = RemotingServices.Marshal(this, string.Format("TemperatureSubcriber_{0}_{1}.rem", Environment.MachineName, Guid.NewGuid()));
p1.Subcribe(_clientRef);
}
}
public class TemperatureProviderProgram
{
static void Main(string[] args)
{
TemperatureProvider tp = new TemperatureProvider();
tp.Start();
}
}
public class TemperatureSubcriberProgram
{
static void Main(string[] args)
{
Console.WriteLine("Press any key to start TemperatureSubcriber.");
Console.ReadLine();
TemperatureSubcriber ts = new TemperatureSubcriber();
ts.Start();
Console.ReadLine();
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
在 WCF 中,通过服务器的“推送”,您实际上正在谈论双工通信;
MarshalByRefObject
在这里基本上是多余的(AFAIK)。 此处页面讨论了各种方案,包括双工/回调。如果问题是 xml(出于某些哲学原因),那么只需使用 NetDataContractSerializer 而不是 DataContractSerializer 可能会有所帮助。
另一种方法是让客户端定期“拉取”数据; 如果您需要支持基本的 http 等,这很有效。
In WCF, with a "push" from the server you're really talking about duplex comms; the
MarshalByRefObject
is largely redundant here (AFAIK). The page here discusses various scenarios, including duplex/callbacks.If the issue is xml (for some philosophical reason), then simply using
NetDataContractSerializer
rather thanDataContractSerializer
might help.The other approach is to have the clients "pull" data periodically; this works well if you need to support basic http, etc.
听起来您想要做的是将 WCF NetTcpBinding 与回调一起使用。
看看这个: http://www.codeproject.com/KB/WCF/ publisher_subscriber.aspx
Michele Bustamante 的《学习 WCF》也非常好。 您可以在她的网站上获取 VS2008 的 Chpt1 以及本书的代码。 Chpt1 将解释/演示设置连接等。 她还有可下载的示例代码。 示例之一是 DuplexPublishSubscribe。
What it sounds like you want to do is use WCF NetTcpBinding with Callbacks.
Take a look at this: http://www.codeproject.com/KB/WCF/publisher_subscriber.aspx
"Learning WCF" by Michele Bustamante is also very good. You can get Chpt1 for VS2008 at her website along with the code for the book. Chpt1 will explain/demo setting up connections and such. She also has downloadable sample code. One of the Samples is a DuplexPublishSubscribe.
您需要稍微修改一下您的逻辑。 如果您想将此应用迁移到
WCF
。 您需要让客户端定期从服务中提取数据。您还需要一个 Windows 服务或应用程序来托管
WCF
,就像您在前面的代码中使用的控制台一样。You will need to modify your logic a bit. If you want to migrate this app to
WCF
. You will need to have clients pull data from the service at regular intervals.You will also need a Windows service or application to host the
WCF
like the console you are using in the previous code.好吧,我构建了实时系统,所以轮询不是一个选项 - 我需要推送数据。
我还发现没有与 System.Runtime.Remoting.ObjRef 等效的 WCF! 这是一种非常有用的类型,它封装了服务端点,并且可以序列化并通过网络传递到其他远程服务。
我想我会坚持使用良好的旧远程处理,直到引入 ObjRef 等效项。
Well I build real time systems so polling is not an option - I need to push data.
Also I am finding there is no WCF equivalent of System.Runtime.Remoting.ObjRef! This is an extremely useful type that encapsulates a service endpoint and can be serialise and passed around the network to other remoting service.
Think I’ll be sticking with good old remoting until the ObjRef equivalent is introduced.
是的,这是真的,只是一处更正..
当任何 MarshalByRefObject 派生对象超出应用程序域时,会自动创建 ObjRef。
因此,在这种情况下,您的 ITemperatureProvider 接口 Subscribe 方法应采用 ITemperatureSubscriber 而不是 objref。
然后在客户端只需调用 p1.Subscribe(this) ,远程处理层将从将被序列化和发送的对象生成 ObjRef。 (发送b参考)
Yes it is true, just one correction..
ObjRefs are created automatically when any MarshalByRefObject derived object is going outside the appdomain.
So in this case your ITemperatureProvider interface Subscribe method shoud take ITemperatureSubscriber instead of objref.
And then on client side just call p1.Subscribe(this) and the remoting layer will generate ObjRef from the object that will be serialized and sent. (sending b reference)