自托管(WinForm)WCF服务如何与主窗体交互?

时间:2012-06-29 18:27:15

标签: .net winforms wcf

我想要实现的简化版本:

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

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

我无法弄明白,我不敢相信如何做到这么简单的事情很难:

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

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

在我看来,它应该像添加对表单的引用一样简单,或者在表单上创建公共函数并从服务类调用它,但我甚至无法弄清楚如何引用Form1在服务类中。

我错过了一些明显的东西吗?我如何引用托管服务的Form1实例?

我走了......的道路。

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

还有其他建议吗?

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

3 个答案:

答案 0 :(得分:11)

使用此方法,您可以完全使用线程安全的应用程序,并且没有任何限制。

服务合同定义

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

服务实施

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

Program.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();
    }
}

答案 1 :(得分:1)

在我看来,正如朋友所说,答案是“simpol”。首先,我甚至不愿意按照您描述的路径,毕竟Web服务提供了与之通信的所有必要方法。在您的Form1(托管您的服务)和托管服务之间添加一个客户端(客户端代码由同一Form1托管),并允许您的客户端使用双工通道与您的服务进行通信。通过这种方式,您的客户端将通过启动长时间运行的请求并通过回调通知来知道是否已将消息发送到您的服务。以下是与双面渠道相关的精彩文章的链接:http://blogs.msdn.com/b/carlosfigueira/archive/2012/01/11/wcf-extensibility-transport-channels-duplex-channels.aspx

P.S:这是一个粗略的建议,让你开始肯定可以改进。

答案 2 :(得分:0)

您可以使用单身人士进行服务吗?如果是这样,你可以像这样实现它:

[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));