2 .Net应用程序之间的有效沟通应用程序、有效、Net

2023-09-03 11:10:19 作者:[ 学校榻了就是晴天 ]

我目前正在写在C#.Net应用程序,它有两个主要组件:

I am currently writing a .Net application in c#, which has two main components:

DataGenerator -a组件产生了大量的数据 浏览器 - 一个WPF应用程序,它能够以可视化的数据,该生成器创建 DataGenerator -a component generating a lot of data Viewer - a WPF application that is able to visualize the data that the generator creates

这两个组成部分目前都在我的解决方案两个不同的项目。此外,我使用,以便在 PRISM 4.0 框架,以使模块出这些组件。

Those two components are currently two seperate projects in my solution. Furthermore, I am using the PRISM 4.0 framework in order to make modules out of those components.

从本质上讲,DataGenerator会产生大量的数据,并发出事件使用的 EventAggregator 从棱镜和浏览器订阅这些事件,并显示为用户准备的数据。

Essentially, the DataGenerator generates a lot of data and sends out events using the EventAggregator from PRISM and the Viewer subscribes to these events and shows the data ready for the user.

现在我的要求略有变化,这两个组件现在会在自己的应用程序中运行(但在同一台计算机上)。我还是想知道所有的通信事件驱动的,我也仍然喜欢用PRISM框架。

Now my requirements have slightly changed and the two components will now run in their own application (but on the same computer). I would still like to have all the communication event-driven and I would also still like to use the PRISM framework.

我的第一个念头是使用 WCF 作为这两个应用程序之间的通信。然而,有一件事,让生活有点困难:

My first thought was to use WCF for the communication between those two applications. However, there is one thing that makes life a bit harder:

的DataGenerator具有绝对的不知道的有关浏览器(和依赖关系的) 的DataGenerator仍然应该工作完全正常,如果我们没有浏览器打开,或者如果我们关闭浏览器应用程序。 在很多事件正在从DataGenerator上升(使用EventAggregator):WCF是足够有效地处理大量的事件在很短时间内金额 the DataGenerator has absolutely no knowledge about the Viewer (and no dependencies) the DataGenerator should still be working perfectly fine if we do not have viewer open, or if we close the viewer application. a lot of events are currently rising from the DataGenerator (using the EventAggregator): Is WCF efficient enough to handle lots of events in a very short amount of time?

基本上,所有这些事件携带的数据是非常简单的字符串,整数和布尔值。莫不是这样做并没有WCF更轻量级的方式?

Basically the data that all those events carry are very simple strings, integer and booleans. Could there be a more lightweight way of doing this without WCF?

最后,这将是很好,如果DataGenerator可以发送这些事件和潜在的多个应用程序订阅了他们(或无)。

Finally, it would be nice if the DataGenerator could send out these events and potentially more than one application subscribes to them (or none).

任何建议和提示是非常AP preciated。

Any suggestions and hints are highly appreciated.

谢谢! 基督教

修改1

我现在创建了两个简单的控制台应用程序(一个托管的服务,并发送消息,另一个接收消息)使用WCF和回调(如已提出)。我将添加工作code,只要我得到这个工作。

I am now creating two simple Console applications (one hosting the service and sending the messages, another one receiving the messages) using WCF and Callbacks (as has been suggested). I will add working code as soon as I get this working.

编辑2

好了 - 好不容易才得到一个简单的程序运行! :)感谢您的帮助,伙计们!这里是code和的照片,其中哪些类:

Okay - Managed to get a simple program running! :) Thanks for your help, guys! Here is the code and a picture of where which classes are:

让我们先从发件人:

在我的应用程序,发送包含了服务接口及其实现。

In my application, the sender contains the service interfaces and their implementations.

IMessageCallback是回调接口:

IMessageCallback is the callback interface:

namespace WCFSender
{
    interface IMessageCallback
    {
        [OperationContract(IsOneWay = true)]
        void OnMessageAdded(string message, DateTime timestamp);
    }
}

ISimpleService是服务合同:

ISimpleService is the service contract:

namespace WCFSender
{
    [ServiceContract(CallbackContract = typeof(IMessageCallback))]
    public interface ISimpleService
    {
        [OperationContract]
        void SendMessage(string message);

        [OperationContract]
        bool Subscribe();

        [OperationContract]
        bool Unsubscribe();
    }
}

SimpleService是ISimpleService执行:

SimpleService is the implementation of ISimpleService:

public class SimpleService : ISimpleService
    {
        private static readonly List<IMessageCallback> subscribers = new List<IMessageCallback>();

        public void SendMessage(string message)
        {
            subscribers.ForEach(delegate(IMessageCallback callback)
            {
                if (((ICommunicationObject)callback).State == CommunicationState.Opened)
                {
                    callback.OnMessageAdded(message, DateTime.Now);
                }
                else
                {
                    subscribers.Remove(callback);
                }
            });
        }

        public bool Subscribe()
        {
            try
            {
                IMessageCallback callback = OperationContext.Current.GetCallbackChannel<IMessageCallback>();
                if (!subscribers.Contains(callback))
                    subscribers.Add(callback);
                return true;
            }
            catch
            {
                return false;
            }
        }

        public bool Unsubscribe()
        {
            try
            {
                IMessageCallback callback = OperationContext.Current.GetCallbackChannel<IMessageCallback>();
                if (!subscribers.Contains(callback))
                    subscribers.Remove(callback);
                return true;
            }
            catch
            {
                return false;
            }
        }
    }

在Program.cs中(在发送方),服务托管,并在消息被发送:

In Program.cs (on the sender side), the Service is hosted and the messages are being send:

[CallbackBehavior(ConcurrencyMode = ConcurrencyMode.Multiple)]
    class Program : SimpleServiceReference.ISimpleServiceCallback, IDisposable
    {
        private SimpleServiceClient client;

        static void Main(string[] args)
        {
            ServiceHost myService = new ServiceHost(typeof(SimpleService));
            myService.Open();
            Program p = new Program();
            p.start();

            Console.ReadLine();
        }

        public void start()
        {
            InstanceContext context = new InstanceContext(this);

            client = new SimpleServiceReference.SimpleServiceClient(context, "WSDualHttpBinding_ISimpleService");

            for (int i = 0; i < 100; i++)
            {
                client.SendMessage("message " + i);
                Console.WriteLine("sending message" + i);
                Thread.Sleep(600);
            }
        }

        public void OnMessageAdded(string message, DateTime timestamp)
        {
            throw new NotImplementedException();
        }

        public void Dispose()
        {
            client.Close();
        }
    }

此外,请注意,服务引用已经被添加到发件人项目的

Furthermore, note that the service reference has been added to the Sender project!

现在,让我们到达接收方:

由于已经在发件人已经完成,我添加了服务引用到项目中。

As has already been done in the Sender, I added the Service Reference to the project.

只有一类,Program.cs的:

There is only one class, Program.cs:

[CallbackBehavior(ConcurrencyMode = ConcurrencyMode.Multiple)]
    class Program : SimpleServiceReference.ISimpleServiceCallback, IDisposable
    {
        private SimpleServiceClient client;

        static void Main(string[] args)
        {
            Program p = new Program();
            p.start();
            Console.ReadLine();
            p.Dispose();
        }

        public void start()
        {
            InstanceContext context = new InstanceContext(this);

            client = new SimpleServiceReference.SimpleServiceClient(context, "WSDualHttpBinding_ISimpleService");
            client.Subscribe();
        }

        public void OnMessageAdded(string message, DateTime timestamp)
        {
            Console.WriteLine(message + " " + timestamp.ToString());
        }

        public void Dispose()
        {
            client.Unsubscribe();
            client.Close();
        }
    }

剩下的最后一件事是在app.config文件。在客户端,在app.config自动通过将服务引用产生的。在服务器端,我也稍微改变了配置,不过是它的部分也自动生成通过添加服务引用。请注意,您需要添加服务引用之前做的修改:

The last thing remaining are the app.config files. On the client side, the app.config is automatically generated by adding the service reference. On the server side, I have slightly changed the config, however parts of it are also auto-generated by adding the service reference. Note that you need to do the changes before adding the service reference:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <system.serviceModel>
        <bindings>
            <wsDualHttpBinding>
                <binding name="WSDualHttpBinding_ISimpleService" closeTimeout="00:01:00"
                    openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
                    bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard"
                    maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
                    messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true">
                    <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
                        maxBytesPerRead="4096" maxNameTableCharCount="16384" />
                    <reliableSession ordered="true" inactivityTimeout="00:10:00" />
                    <security mode="Message">
                        <message clientCredentialType="Windows" negotiateServiceCredential="true"
                            algorithmSuite="Default" />
                    </security>
                </binding>
            </wsDualHttpBinding>
        </bindings>
        <client>
            <endpoint address="http://localhost:8732/Design_Time_Addresses/WCFSender/SimpleService/"
                binding="wsDualHttpBinding" bindingConfiguration="WSDualHttpBinding_ISimpleService"
                contract="SimpleServiceReference.ISimpleService" name="WSDualHttpBinding_ISimpleService">
                <identity>
                    <dns value="localhost" />
                </identity>
            </endpoint>
        </client>
        <behaviors>
            <serviceBehaviors>
                <behavior name="MessageBehavior">
                    <serviceMetadata httpGetEnabled="true" />
                    <serviceDebug includeExceptionDetailInFaults="false" />
                </behavior>
            </serviceBehaviors>
        </behaviors>
        <services>
            <service name="WCFSender.SimpleService" behaviorConfiguration="MessageBehavior">
                <endpoint address="" binding="wsDualHttpBinding" contract="WCFSender.ISimpleService">
                    <identity>
                        <dns value="localhost" />
                    </identity>
                </endpoint>
                <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
                <host>
                    <baseAddresses>
                        <add baseAddress="http://localhost:8732/Design_Time_Addresses/WCFSender/SimpleService/" />
                    </baseAddresses>
                </host>
            </service>
        </services>
    </system.serviceModel>
</configuration>

重要提示: 我成功地实现使用教程,这两个非常简单的应用程序。上述code对我的作品,希望可以帮助别人理解WCF回调。它不是非常好写入code和不应完全用!这仅仅是一个简单的示例应用程序。

IMPORTANT: I managed to implement these two very simple applications using the tutorials. The above code works for me and hopefully helps others to understand WCF callback. It is not extremely well-written code and should not be used entirely! It is just a simplistic example app.

推荐答案

不要担心性能,WCF可如果配置得当达到非常高的吞吐量。使用回调的事件:http://www.switchonthe$c$c.com/tutorials/wcf-tutorial-events-and-callbacks

Dont worry about performance, wcf can reach very high throughput if configured properly. Use callbacks for your events : http://www.switchonthecode.com/tutorials/wcf-tutorial-events-and-callbacks