【问题标题】:How can a self-hosted (WinForm ) WCF service interact with the main form?自托管 (WinForm) WCF 服务如何与主窗体交互?
【发布时间】:2012-06-29 18:27:14
【问题描述】:

我想要实现的简化版本:

  • 我有一个 WinForms 应用程序在后台运行隐藏 (Visible = false)。
  • 它只有一个Form,我保留了默认名称-Form1
  • 此 WinForms 应用托管 WCF 服务。现在我们将其称为 Listener 服务。
  • 此侦听器服务有一个名为“DisplayAlert()”的函数,该函数公开为服务函数
  • 另一台计算机上的应用通过标准 WCF 服务调用向侦听器服务发送消息

我已经完成了上述所有工作。在调用 DisplayAlert() 函数时,我可以单步执行代码并观察消息流。

我想不通,我不敢相信要找到如何做这么简单的事情这么难:

- 我希望托管服务中的 DisplayAlert() 函数直接与托管它的 WinForm 交互以使表单可见。

我要做的就是将 Visibility 设置为 true,然后在 WinForm 上调用另一个函数。

在我看来,这应该就像添加对表单的引用一样简单,或者在表单上创建一个公共函数并从服务类调用它,但我什至不知道如何从在服务类中。

我是否遗漏了一些明显的东西?我如何引用托管服务的 Form1 的实例?

我已经走上了……的道路

  • 在ListenerService中创建一个事件(AlertReceived,virtual void OnAlertReceived),想着在Form上,我可以添加一个事件处理程序。
    • 没有骰子。我没有直接实例化 ListenerService 类,它在 ServiceHost 中运行。
  • 尝试从类中引用 Application 对象,我认为我可以将其引用为 Application.Form1,但不行。我什至无法从服务类中看到 Application 对象。
    • 我可能在这里遗漏了一些明显的东西,但我不确定。

还有其他建议吗?

如果有帮助,我可以添加代码。

【问题讨论】:

  • 如果没有办法直接做到这一点,我将把它作为答案并重新考虑设计。

标签: .net winforms wcf


【解决方案1】:

使用这种方法,您拥有一个完全线程安全的应用程序,并且您没有任何限制。

服务合同定义

[ServiceContract]
public interface IService
{
    [OperationContract]
    void DisplayAlert();
}

服务实现

public class Service:IService
{
    public void DisplayAlert()
    {
        var form = Form1.CurrentInstance;
        form.MySynchronizationContext.Send(_ => form.Show(), null);
    }
}

程序.cs

[STAThread]
static void Main()
{        
    var host = new ServiceHost(typeof (Service));
    host.Open();

    Application.SetCompatibleTextRenderingDefault(false);
    Application.EnableVisualStyles();
    Application.Run(new Form1());
 }

表单实现

public partial class Form1 : Form
{
    public static Form1 CurrentInstance;
    public SynchronizationContext MySynchronizationContext;
    private bool showForm = false;

    public Form1()
    {
        InitializeComponent();
        MySynchronizationContext = SynchronizationContext.Current;
        CurrentInstance = this;
    }

    // use this method for hiding and showing if you want this form invisible on start-up
    protected override void SetVisibleCore(bool value)
    {
        base.SetVisibleCore(showForm ? value : showForm);
    }

    public void Show()
    {
        showForm = true;
        Visible = true;   
    }

    public void Hide()
    {
        showForm = true;
        Visible = true;
    }
}

客户

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("Press Enter to show form");
        Console.ReadLine();

        var client = new ServiceClient();
        client.DisplayAlert();
    }
}

【讨论】:

    【解决方案2】:

    在我看来,正如一位朋友所说,答案是“simpol”。首先,我什至不会费心遵循您描述的路径,毕竟 Web 服务提供了与之通信的所有必要手段。在您的 Form1(托管您的服务)和您的托管服务之间添加一个客户端(其中客户端代码由同一个 Form1 托管)并允许您的客户端使用双工通道与您的服务进行通信。通过这种方式,您的客户端将通过发起一个长时间运行的请求并通过回调获得通知来了解是否有消息发送到您的服务。这是与双工通道相关的精美文章的链接:http://blogs.msdn.com/b/carlosfigueira/archive/2012/01/11/wcf-extensibility-transport-channels-duplex-channels.aspx

    P.S:这是一个粗略的建议,可以帮助您入门,肯定可以改进。

    【讨论】:

    • 谢谢!我们想避免很多开放的渠道,并为此进行投票。带宽与我们零售点的十亿个其他功能相关联,因此在商店级别,我们确实需要一些东西,只是坐下来听,直到有理由发送警报。在另一种情况下,我会使用你的建议,所以 +1。
    【解决方案3】:

    您可以为您的服务使用单例吗?如果是这样,您可以像这样实现它:

    [ServiceContract]
    [ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)]
    public class MyClass : IMyClass
    {
        Form1 _f;
        public MyClass(Form1 f)
        {
            _f = f;
        }
    
        [OperationContract]
        public void Alert(string mess)
        {
            _f.Text = mess;
        }
    }
    

    然后当你设置你的服务主机时,你将它实例化并传递给它:

    MyClass c = new MyClass(this);
    string baseAddress = "http://localhost:12345/Serv";
    var host = new ServiceHost(c, new Uri(baseAddress));
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-03-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多