Winform应用程序与服务通信

本文关键字:通信 服务 应用程序 Winform | 更新日期: 2023-09-27 17:57:20

我需要用 C# 编写一个服务,即使没有人登录,该服务也将始终在 PC 上运行。我需要编写一个 c# winform 应用程序,该应用程序将在用户登录时自动运行,并允许用户与服务交互。我建议的解决方案是在服务中构建一个 WCF 服务器,并将一个 WCF 客户端写入 winform 应用程序。然后,这将允许Winform应用程序和服务之间的交互。这是最好/最简单的方法吗?

Winform应用程序与服务通信

是的

- WCF 可能是 WinForms 客户端和服务后端之间通信的最简单解决方案。

您的主要选择是: 1. TCP 套接字(较低级别,可能需要更多样板代码)。 2. 消息传递中间件,如 MSMQ/ActiveMQ NMS(涉及添加更多第三方库)

如果你使用 WCF,根据我的经验,有一些陷阱/建议:

  1. 不要在服务器中同步处理 WCF 请求,而是异步处理它们(如果代码是线程安全的),或者通过单个后台处理队列处理它们(如果代码不是线程安全的)。这有助于避免超时问题(这可能导致 WCF 出错),以及同时从多个线程触发 WCF 请求的问题。
  2. 不要忘记,客户端和服务器中可能需要 WCF 接口。如果您希望服务器能够将任何类型的异步通信发送回客户端,则需要这样做。
  3. 您可以使用 WCF 设置发布/订阅机制,但这有点棘手。下面是一个代码示例:

接口

//Server interface
[ServiceContract(CallbackContract = typeof(IGUIService))]
public interface IServerService
{
    [OperationContract(IsOneWay = true)]
    void Subscribe();
    [OperationContract(IsOneWay = true)]
    void Unsubscribe();
    ...
}
//Client interface
[ServiceContract]
public interface IGUIService
{
    [OperationContract(IsOneWay = true)]
    void MessageCallback(string Message);
}

客户端在启动时需要调用 Subscribe(),在关闭时调用 Unsubscribe()。处理此问题的相应服务器代码是:

[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)]
public class ServerService : IServerService
{
    internal event SettingsUpdatedHandler SettingsUpdated;
    internal delegate void SettingsUpdatedHandler(ServerService adminPort, EventArgs e);
    private static List<IGUIService> Clients = new List<IGUIService>();
    public void Subscribe()
    {
            IGUIService callback = OperationContext.Current.GetCallbackChannel<IGUIService>();
            if(!Clients.Contains(callback))
                Clients.Add(callback);
    }
    public void Unsubscribe()
    {
            IGUIService callback = OperationContext.Current.GetCallbackChannel<IGUIService>();
            if (Clients.Contains(callback))
                Clients.Remove(callback);
    }
}

然后,要将消息从服务器发送到所有连接的客户端,请执行以下操作:

    internal void SendMessage(string message)
    {
            for(int i=Clients.Count - 1; i >= 0; i--)
            {
                IGUIService callback = Clients[i];
                if (((ICommunicationObject)callback).State == CommunicationState.Opened)
                    callback.MessageCallback(message);
                else
                    Clients.RemoveAt(i);
            }
    }

如果你愿意,你也可以使用web api。但请注意,如果使用 Web api,则可以使用事务。

但是Web api和wcf都很好。

WCF 服务器:托管在服务器中的 Windows 服务中。

WCF 客户端:Winform 应用程序。并将程序的快捷方式放在文件夹"C:''Documents and Settings[用户名]''Start Menu''Programs''Startup"(Windows XP)中。程序将在用户登录时自动运行。

是否需要维护服务中的状态?如果没有,那么您不仅可以在IIS中托管或自行托管wcf,Web api甚至服务堆栈服务。 此外,该服务是否会被多个客户使用?持久性存储访问是否需要存在于另一个进程中,如果不需要,那么"进程中"也很好,没有所有与服务相关的开销。

你所拥有的,是两个需要相互通信的进程。其中一个进程恰好是Windows服务,而另一个是Windows应用程序。这是进程间通信的经典问题。有许多可用的解决方案,可能是最受欢迎的:

  1. WCF,你已经提到过了。Windows 服务实现 WCF 服务的主机,应用与公开的服务通信。下面是如何实现这一点的一个很好的例子。
  2. 命名管道,古老且受到许多人的青睐。查看此处和此处的一些示例。

其他更奇特的例子:

  1. 自定义 TCP 端口
  2. Win32 RPC。可以使用像此库类似的 .NET 包装器。
  3. MSMQ
  4. 文件系统。一个进程写入定义的位置,另一个进程侦听该位置。您可以使用序列化编写双方都能理解的简单消息,甚至整个对象。
  5. 数据库。第4点的变体,使用提供数据库功能的第三个过程。

鉴于 WCF 是相当成熟的技术,具有足够的性能,使用 .NET 构建并且相当容易实现,这似乎是一个自然的选择。