简体   繁体   English

WCF作为Windows服务组件

[英]WCF as a Windows Service component

I am looking for best practices here. 我在这里寻找最佳做法。 I am developing a Windows Service, which is actively monitoring several things and is configured through a database where it also writes logs and status changes and such. 我正在开发Windows服务,该服务正在主动监视多个事物,并通过数据库进行配置,该数据库还写入日志和状态更改等。

Now I want to connect a GUI as a client application to change configuration or to get the GUI alerted when certain things occur. 现在,我想将GUI作为客户端应用程序进行连接,以更改配置或在发生某些情况时使GUI收到警报。 I thought of using WCF for this. 我想到了为此使用WCF。

But I am not sure how to implement this. 但是我不确定如何实现这一点。 I can create a WCF Service, I have already some experience with that, I even build a callback already. 我可以创建WCF服务,对此我已有一定的经验,甚至已经建立了回调。 But as the WCF Service uses stateless connection, all objects concerning it are lost after each connection, so I would have to declare most things static which feels like a hack. 但是由于WCF服务使用无状态连接,因此与该状态有关的所有对象在每次连接后都会丢失,因此我将不得不声明大多数静态的东西,感觉就像是黑客一样。

On the other hand I could use my already created Windows Service and add a WCF component to it. 另一方面,我可以使用已经创建的Windows Service并向其中添加WCF组件。 But I fail to understand how to connect the persistent objects from the service to the wcf. 但是我不明白如何将持久对象从服务连接到wcf。

So basically I dont understand how to build a peristant running Service, which has a WCF component which (thats how I think at least) is created on a connection event, processes and dies after that, but has access to information/objects from the 'parent' Service. 因此,基本上我不理解如何构建一个持久运行的服务,该服务具有WCF组件(至少我认为是这样),该组件是在连接事件上创建的,之后会进行处理和死亡,但是可以从“家长服务。 Can this be done or do I bend and twist the WCF concept too much in this case? 在这种情况下可以做到吗?或者我会过度弯曲和扭曲WCF概念吗?

Edit: To clerify: I can do stateless connections. 编辑:澄清一下:我可以进行无状态连接。 But how to keep the callback alive? 但是如何使回调保持活力? If i put all 'intelligence' into the WFC Service, it is not running before someone connects to it (the constructor is not called before that). 如果我将所有“智能”都放入WFC服务中,则在有人连接到它之前它不会运行(在此之前未调用构造函数)。 If I i put my intelligence into a 'normal' windows service, I do not know, how to keep the calback connection alive nor do I know how to trigger functions within the WCF service from outside. 如果我将自己的智慧投入到“正常” Windows服务中,我将不知道如何保持回调连接保持活动状态,也不知道如何从外部触发WCF服务中的功能。

[SECOND EDIT]: This is what I tried today. [第二编辑]:这是我今天尝试过的。 Basically I host the WCF in a ConsoleApp (for testing). 基本上,我将WCF托管在ConsoleApp中(用于测试)。 A Client can connect and the WCF Server creates a Callback then. 客户端可以连接,然后WCF服务器创建一个回调。 The hosting application itself has a reference to the WCF service and can push Messages into it. 托管应用程序本身具有对WCF服务的引用,可以将消息推送到其中。 The WF itself can then check if there is a callback present, and if so puts the message on list, which is processed in a thread. 然后,WF本身可以检查是否存在回调,如果存在,则将该消息放在列表中,并在线程中进行处理。 It complies but wont start due to an accessing error on the tcp port when calling host.Open(): 它符合要求,但由于调用host.Open()时tcp端口上的访问错误而无法启动:

Der Zugriff auf einen Socket war aufgrund der Zugriffsrechte des Sockets unzulässig) beim Abhören an IP-Endpunkt=0.0.0.0:8732. 如果您的套接字无法访问IP地址,则IP地址为End-amptkt = 0.0.0.0:8732。

English translation by Google Translate: Google翻译的英文翻译:

Access to a socket was invalid) when listening on IP Endpoint by its access permissions of the socket 通过套接字对套接字的访问权限侦听IP端点时,对套接字的访问无效)

This is my source so far: Service Interface: 到目前为止,这是我的信息来源:服务接口:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;

namespace WCFHostInfo

{

    [ServiceContract]
    public interface IWCFService
    {
        [OperationContract]
        bool informClient(IpEvent value);

        [OperationContract]
        bool connectClient();

        [OperationContract]
        bool disconnectClient();
    }

    public interface IClientCallback
    {
        [OperationContract]
        void onCallback(IpEvent value);
    }

    [DataContract]
    public class IpEvent
    {
        String _ip;
        DateTime _time;

        [DataMember]
        public String ip
        {
            get { return _ip; }
            set { _ip = value; }
        }

        [DataMember]
        public DateTime time
        {
            get { return _time; }
            set { _time = value; }
        }
    }        
}

This is the service: 这是服务:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using System.Threading;

namespace WCFHostInfo
{
    [ServiceBehavior (ConcurrencyMode = ConcurrencyMode.Reentrant)]
    public class WCFService : IWCFService
    {
        public static IClientCallback callback;
        private static Object queueLock = new Object();
        private static bool thredStop;
        private Thread queueThread;
        private static List <IpEvent> iplist = new List <IpEvent>();

        public WCFService()
        {

        }

        public bool disconnectClient()
        {
            thredStop = true;
            queueThread.Join();
            callback = null;
            return true;
        }

        public bool informClient(IpEvent value)
        {
            if (callback != null)
            {
                lock (queueLock)
                {
                    iplist.Add(value);
                }
                return true;
            }
            return false;
        }

        private void pushClient()
        {
            while (!thredStop)
            {
                bool sleep = true;
                lock (queueLock)
                {
                    if (iplist.Count != 0)
                    {
                        sleep = false;
                    }
                }
                if (sleep)
                {
                    Thread.Sleep(250);
                }
                else
                {
                    List<IpEvent> worklist = new List<IpEvent>();
                    lock (queueLock)
                    {
                        worklist = iplist;
                        iplist = new List<IpEvent>();
                    }
                    foreach (IpEvent item in worklist)
                    {
                        callback.onCallback(item);
                    }
                }
            }
        }

        public bool connectClient()
        {
            callback = OperationContext.Current.GetCallbackChannel<IClientCallback>();
            queueThread = new Thread(pushClient);
            thredStop = false;
            queueThread.Start();
            return true;
        }
    }

}

This is the hosting console app: 这是托管控制台应用程序:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using WCFHostInfo;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.ServiceModel.Configuration;
using System.Threading;
using TestKonsole.ServiceReference1;

namespace TestKonsole
{
    class Program
    {
        static WCFServiceClient client;
        static bool stopThread;

        static void Main(string[] args)
        {
            client = new WCFServiceClient();
            stopThread = false;
            ServiceHost myhost = new ServiceHost(typeof(WCFHostInfo.WCFService));
            NetTcpBinding netTcp = new NetTcpBinding();

            netTcp.Security.Mode = SecurityMode.None;
            netTcp.Security.Message.ClientCredentialType = MessageCredentialType.None;
            netTcp.Security.Transport.ProtectionLevel = System.Net.Security.ProtectionLevel.None;

            netTcp.MaxReceivedMessageSize = 2147483647;
            myhost.AddServiceEndpoint(typeof(WCFHostInfo.IWCFService), netTcp, "net.tcp://localhost:8732/serv");
            ServiceMetadataBehavior beh = new ServiceMetadataBehavior();
            myhost.Description.Behaviors.Add(beh);

            Thread pushThread = new Thread(push);


            myhost.Open(); 
            //This is where the exception occures...
            Console.WriteLine("Host opened");
            Console.ReadLine();
            stopThread = true;
            pushThread.Join();
            myhost.Close();
            Console.WriteLine("Host closed");
            Console.ReadLine();

        }

        private static void push() 
        {
            while (!stopThread)
            {
                Thread.Sleep(5000);
                IpEvent ev = new IpEvent();
                ev.ip = "192.156.45.9";
                ev.time = DateTime.Now;
                bool res = client.informClient(ev);
                if (res)
                {
                    Console.WriteLine("Client informed!");
                }
                else
                {
                    Console.WriteLine("No client connected.");
                }
            }
        }
    }
}

[EDIT 3] I can manage to create a service reference in the hosting app now. [编辑3]现在,我可以在托管应用中创建服务参考。 But i cant send anything because Visual Studio complains at runtime that the endpoint is not known. 但是我无法发送任何内容,因为Visual Studio在运行时抱怨端点未知。 Perhaps someone cann have a look at my app.config file: Server: 也许有人不能看一下我的app.config文件:服务器:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>

  <system.web>
    <compilation debug="true" />
  </system.web>

  <system.serviceModel>
    <services>
      <service behaviorConfiguration="PaewemaZeitWatcher.Service1Behavior"
        name="WCFHostInfo.WCFService">
        <endpoint address="" binding="netTcpBinding" contract="WCFHostInfo.IWCFService">
          <identity>
            <dns value="localhost" />
          </identity>
        </endpoint>
        <endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange" />
        <host>
          <baseAddresses>
            <add baseAddress="net.tcp://localhost:8732/TestWCF/" />
          </baseAddresses>
        </host>
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="PaewemaZeitWatcher.Service1Behavior">

          <serviceMetadata httpGetEnabled="false"/>

          <serviceDebug includeExceptionDetailInFaults="False" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>

</configuration>

Client: 客户:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <system.serviceModel>
        <bindings>
            <netTcpBinding>
                <binding name="NetTcpBinding_IWCFService" />
            </netTcpBinding>
        </bindings>
        <client>
            <endpoint address="net.tcp://localhost:8732/TestWCF/
             "binding="netTcpBinding"
                bindingConfiguration="NetTcpBinding_IWCFService"
                contract="ServiceReference1.IWCFService"
                name="NetTcpBinding_IWCFService">
                <identity>
                    <dns value="localhost" />
                </identity>
            </endpoint>
        </client>
    </system.serviceModel>
</configuration>

I honestly cant see through this any more because I think my need is a quite common one (existing stand alone service, where one can attach a gui to, which receives calls) but I seem the first one ever to implement this. 老实说,我再也看不到这一点,因为我认为我的需求是很普通的(现有的独立服务,可以在其中附加gui并接收呼叫),但是我似乎是第一个实现此需求的人。

[LAST EDIT] I removed this lines from the hosting app [最后编辑]我从托管应用中删除了这些行

netTcp.Security.Mode = SecurityMode.None;
netTcp.Security.Message.ClientCredentialType = MessageCredentialType.None;
netTcp.Security.Transport.ProtectionLevel = System.Net.Security.ProtectionLevel.None;
netTcp.MaxReceivedMessageSize = 2147483647;

Now I can connect to the WCF even from the hosting application but I cant handle two connections at once. 现在,我什至可以从托管应用程序连接到WCF,但是我无法一次处理两个连接。 When my actual client tries to connect I get a communication exception with a completely irrational timeout value of 00:00:59.999 although the Exception occurs half a second after I start the program, with no inner exception and ABSOLUTELY NO CLUE on what has happened. 当我的实际客户端尝试连接时,我收到了一个完全不合理的超时值00:00:59.999的通信异常,尽管该异常发生在我启动程序后半秒钟,没有内部异常,并且对发生的事情绝对没有线索。 I spend the last 2 hours finding dozens of people on Google who all got the exception, almost ever time due to another cause. 我花了最后2个小时的时间,在Google上找到了数十个人,几乎都是由于其他原因,所有这些人都例外。 I changed maxConnections, maxMessageSize etc. several times without any change and I don't see, how to debug this. 我多次更改了maxConnections,maxMessageSize等,没有任何更改,但我看不到如何调试它。

I must say I am deeply agitated, because this is impossible to debug, and again I fell I have to twist and bend WCF because I just want more then a stupid connectionless HTTP transaction. 我必须说我非常激动,因为这不可能调试,而我又一次不得不屈服于WCF,因为我只想要一个愚蠢的无连接HTTP事务。 Anybody PLEASE SHARE on how to use this. 任何人都请分享如何使用此功能。 I cant be the first one with this requirement. 我不能成为第一个满足此要求的人。 If I can't get into this by tomorrow morning I will implement a TCP socket for this BECAUSE THIS WOULD ALREADY BE DONE by now if I had started that way right away. 如果到明天早上我不能解决这个问题,那么我将为此实现一个TCP套接字,因为如果我立即开始这样做的话,现在就已经做好了。 Sorry for being deeply frustrated right now. 对不起,现在感到沮丧。

[QUITTING ON THIS] I spend another day debugging without success. [退出]我花了另一天的时间进行调试,但没有成功。 Since the responses are so small my conclusion is, that WCF is never used this way. 由于响应非常小,我的结论是,永远不会以这种方式使用WCF。 I get the feeling WCF is a fancy toy for Webrequests nothing more. 我觉得WCF只是Webrequests的花哨玩具。 No example on the web features my usecase so I dump it. 网络上没有示例可以使用我的用例,因此我将其转储。 Have to deliver a prototype next week and i cant play around any longer. 下周必须交付一个原型,我不能再玩了。

This is a hard question to answer, since it is so abstract. 这是一个很难回答的问题,因为它是如此抽象。

The short answer is, Yes! 简短的答案是,是的! You can and should implement a WCF endpoint on your Windows service for your GUI to talk to. 您可以并且应该在Windows服务上实现WCF端点,以便GUI与之对话。

You shouldn't need to make anything static. 您不需要使任何静态内容。 As far as connecting to your persistent objects, you will need to create serializable data contracts for each of your "persistent" objects, and send and receive those via WCF. 至于连接到持久对象,您将需要为每个“持久”对象创建可序列化的数据协定,并通过WCF发送和接收这些协定。

I don't see a need for two separate services, just sounds like a lot of work. 我认为不需要两个单独的服务,听起来像是很多工作。

Let me know if I can provide any more information or clarify anything! 让我知道是否可以提供更多信息或澄清任何内容!

UPDATE: Your clients should be calling a "Subscribe" function that puts their InstanceContext into a subscription list, that you can then call the callbacks on. 更新:您的客户端应该调用一个“订阅”函数,将其InstanceContext放入订阅列表,然后可以在其上调用回调。 Doing this makes the connection stateful. 这样做会使连接成为有状态的。 You may need to write your own proxy to make all this work, the generated ones don't do duplex comms very well. 您可能需要编写自己的代理服务器才能完成所有这些工作,生成的代理服务器不能很好地进行双工通信。 I would also recommend using the net:tcp binding if you arent' already. 如果已经没有,我也建议使用net:tcp绑定。

Here is a reference for duplex services if you haven't seen it already, MSDN 如果您还没有看到双工服务,请参考这里, MSDN

Not quite sure what the best answer is, but I've a feeling that you need to read up on SignalR. 不确定最佳答案是什么,但我觉得您需要阅读SignalR。 From my vague recollection I think this can perform push notifications (somehow). 从我模糊的回忆中,我认为它可以执行推送通知(以某种方式)。 Apologies if I'm completely wrong!! 抱歉,如果我完全错了!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM