【问题标题】:Create a self hosted WCF Service inside a Windows Form在 Windows 窗体中创建自托管 WCF 服务
【发布时间】:2019-03-02 18:48:05
【问题描述】:

如果我将此代码用于自己在控制台应用程序中托管 WCF 服务,它就可以工作。我运行主机应用程序,然后从另一个应用程序(我称为客户端应用程序)运行我可以从 Visual Studio > 解决方案资源管理器 > 添加服务参考 > http://10.131.131.14:8080/sendKioskMessage > 单击开始,添加服务没有问题,然后从客户端应用程序(这是一个 Windows 窗体)使用它

但是如果我在 Windows 窗体中运行相同的代码,我首先运行 (SELF HOST WCF) Windows 窗体应用程序,然后从 Visual Studio 中的另一个应用程序(客户端应用程序)我尝试从 ADD SERVICE 添加服务引用解决方案资源管理器中的 REFERENCE (与之前的工作方式相同,但使用控制台应用自托管)但会引发以下错误:

*

尝试在以下位置查找服务时发生错误(详细信息) http://10.131.131.14:8080/sendKioskMessage.

(如果我单击详细信息链接,则会显示以下内容:)

下载时出错 'http://10.131.131.14:8080/sendKioskMessage/$元数据'。无法 连接到远程服务器。元数据包含一个引用 无法解决:'http://10.131.131.14:8080/sendKioskMessage'。 没有端点监听 http://10.131.131.14:8080/sendKioskMessage 可以接受 信息。这通常是由不正确的地址或 SOAP 操作引起的。 有关更多详细信息,请参阅 InnerException(如果存在)。无法连接到 远程服务器。如果在当前解决方案中定义了服务, 尝试构建解决方案并再次添加服务引用。

*

我使用的 IP 是运行这两个应用程序的电脑的 IP。我还使用了 localhost 而不是我的实际 IP,结果相同。

Windows 窗体代码(无法从其他应用添加服务):

public partial class KioskosServerForm : Form
    {


        [ServiceContract]
        public interface IKioskMessageService
        {
            [OperationContract]
            string SendKioskMessage(string message);
        }

        public class KioskMessageService : IKioskMessageService
        {
            public string SendKioskMessage(string message)
            {
                return string.Format("Message sent: {0}", message);
            }
        }

        public KioskosServerForm()
        {
            InitializeComponent();
        }

        private void KioskosServerForm_Load(object sender, EventArgs e)
        {
            Uri baseAddress = new Uri("http://10.131.131.14:8080/sendKioskMessage");

            try
            {
                // Create the ServiceHost.
                using (ServiceHost host = new ServiceHost(typeof(KioskMessageService), baseAddress))
                {
                    // Enable metadata publishing.
                    ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
                    smb.HttpGetEnabled = true;
                    smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy15;
                    host.Description.Behaviors.Add(smb);

                    // Open the ServiceHost to start listening for messages. Since
                    // no endpoints are explicitly configured, the runtime will create
                    // one endpoint per base address for each service contract implemented
                    // by the service.
                    host.Open();
                }
            }
            catch (Exception exp)
            {
                MessageBox.Show(exp.InnerException.Message);
            }
        }
    }

控制台应用代码(有效!我可以从其他客户端应用添加服务):

[ServiceContract]
public interface IKioskMessageService
{
    [OperationContract]
    string SendKioskMessage(string message);
}

public class KioskMessageService : IKioskMessageService
{
    public string SendKioskMessage(string message)
    {
        return string.Format("Message sent: {0}", message);
    }
}

class Program
{
    static void Main(string[] args)
    {
        Uri baseAddress = new Uri("http://localhost:8080/sendKioskMessage");

        // Create the ServiceHost.
        using (ServiceHost host = new ServiceHost(typeof(KioskMessageService),baseAddress))
        {
            // Enable metadata publishing.
            ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
            smb.HttpGetEnabled = true;
            smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy15;
            host.Description.Behaviors.Add(smb);

            // Open the ServiceHost to start listening for messages. Since
            // no endpoints are explicitly configured, the runtime will create
            // one endpoint per base address for each service contract implemented
            // by the service.
            host.Open();

            Console.WriteLine("The service is ready at {0}", baseAddress);
            Console.WriteLine("Press <Enter> to stop the service.");
            Console.ReadLine();

            // Close the ServiceHost.
            host.Close();
        }
    }
}

如果服务在控制台应用程序中自托管,我不知道为什么我可以使用该服务,但如果服务在 Windows 窗体中自托管,我无法添加它。

我将非常感谢您从 Windows From 实现此目标的帮助,因为我需要从 Windows 窗体自行托管 WCF 服务,而不是控制台应用程序。

我正在使用 Visual Studio 2017,.Net Framework 4.6.1

提前谢谢大家!!

【问题讨论】:

  • 嗨 MickyD,感谢您的回复。
  • 这只是一项服务,我创建了一个 Windows 窗体应用程序,将其称为应用程序“A”来自托管服务。然后我创建一个新的 Windows 窗体应用程序,将其称为应用程序“B”,以使用应用程序“A”自托管的服务。它不起作用!...所以我关闭了“A”并创建了一个控制台应用程序让我们将其称为应用程序“C”并将相同的代码从应用程序“A”(它是 Windows 窗体)复制到应用程序“C”,即控制台应用程序。运行它,然后尝试从应用程序“B”使用自托管服务(现在在应用程序“C”中运行)并且它可以工作。就像我说的,我对所有应用程序都使用了 4.6.1。我尝试 LocalHost 和我的 IP 地址只是为了测试,

标签: c# visual-studio web-services wcf self-hosting


【解决方案1】:

TL;DR控制台应用程序可以正常工作,因为您在关闭服务之前有延迟; WinForms 主机没有


您的控制台 WCF 主机服务工作的原因是您启动托管并继续直到 Console.ReadLine() 行:

host.Open();

Console.WriteLine("The service is ready at {0}", baseAddress);
Console.WriteLine("Press <Enter> to stop the service.");
Console.ReadLine();  // <-------- program waits here

// Close the ServiceHost.
host.Close();

...之后服务被拆除。在此之前,您的其他客户端可以正常连接并添加服务引用。

WinForms 应用没有这样的延迟:

private void KioskosServerForm_Load(object sender, EventArgs e)
{
    Uri baseAddress = new Uri("http://10.131.131.14:8080/sendKioskMessage");

    try
    {
        // Create the ServiceHost.
        using (ServiceHost host = new ServiceHost(typeof(KioskMessageService), baseAddress))
        {
            // Enable metadata publishing.
            ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
                smb.HttpGetEnabled = true;
                smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy15;
                host.Description.Behaviors.Add(smb);

            // Open the ServiceHost to start listening for messages. Since
            // no endpoints are explicitly configured, the runtime will create
            // one endpoint per base address for each service contract implemented
            // by the service.
            host.Open();  // <------ opened here
        } // <------ shutdown here
     } 
     catch (Exception exp)
     {
         MessageBox.Show(exp.InnerException.Message);
     }
}

...当代码超出using 块的范围时,它会立即关闭。 using 将自动调用 Dispose() 上的 host 对象,该对象又调用 Close()。

考虑将主机放入这样的变量中:

ServiceHost _host;  // <---------- new!

private void KioskosServerForm_Load(object sender, EventArgs e)
{
    Uri baseAddress = new Uri("http://10.131.131.14:8080/sendKioskMessage");

    try
    {
        // Create the ServiceHost.
        _host = new ServiceHost(typeof(KioskMessageService), baseAddress))
        // Enable metadata publishing.
        ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
        smb.HttpGetEnabled = true;
        smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy15;
       _host.Description.Behaviors.Add(smb);

        // Open the ServiceHost to start listening for messages. Since
        // no endpoints are explicitly configured, the runtime will create
        // one endpoint per base address for each service contract implemented
        // by the service.
        _host.Open();
     }
     catch (Exception exp)
     {
         MessageBox.Show(exp.InnerException.Message);
     }
 }

稍后,您可以通过调用Close 来关闭_host 实例。

【讨论】:

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