【问题标题】:Calling WCF Service using NetTcpBinding from the same winform从同一个 winform 使用 NetTcpBinding 调用 WCF 服务
【发布时间】:2018-04-25 20:51:39
【问题描述】:

大家好,我有以下代码,它允许我为 WCF 服务启动一个临时 Web 服务,而无需自己启动 IIS Express。

但是,下面的代码可以正常工作如果我在另一个 winform 中获取数据。将相同的代码复制到 WCF 服务 winform 会导致它在尝试发送患者索引号时冻结。

类代码(Class1.cs):

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

/*
    HOW TO HOST THE WCF SERVICE IN THIS LIBRARY IN ANOTHER PROJECT
    You will need to do the following things: 
    1)    Add a Host project to your solution
        a.    Right click on your solution
        b.    Select Add
        c.    Select New Project
        d.    Choose an appropriate Host project type (e.g. Console Application)
    2)    Add a new source file to your Host project
        a.    Right click on your Host project
        b.    Select Add
        c.    Select New Item
        d.    Select "Code File"
    3)    Paste the contents of the "MyServiceHost" class below into the new Code File
    4)    Add an "Application Configuration File" to your Host project
        a.    Right click on your Host project
        b.    Select Add
        c.    Select New Item
        d.    Select "Application Configuration File"
    5)    Paste the contents of the App.Config below that defines your service endoints into the new Config File
    6)    Add the code that will host, start and stop the service
        a.    Call MyServiceHost.StartService() to start the service and MyServiceHost.EndService() to end the service
    7)    Add a Reference to System.ServiceModel.dll
        a.    Right click on your Host Project
        b.    Select "Add Reference"
        c.    Select "System.ServiceModel.dll"
    8)    Add a Reference from your Host project to your Service Library project
        a.    Right click on your Host Project
        b.    Select "Add Reference"
        c.    Select the "Projects" tab
    9)    Set the Host project as the "StartUp" project for the solution
        a.    Right click on your Host Project
        b.    Select "Set as StartUp Project"

    ################# START MyServiceHost.cs #################

    using System;
    using System.ServiceModel;

    // A WCF service consists of a contract (defined below), 
    // a class which implements that interface, and configuration 
    // entries that specify behaviors and endpoints associated with 
    // that implementation (see <system.serviceModel> in your application
    // configuration file).

    internal class MyServiceHost
    {
        internal static ServiceHost myServiceHost = null;

        internal static void StartService()
        {
            //Consider putting the baseAddress in the configuration system
            //and getting it here with AppSettings
            Uri baseAddress = new Uri("http://localhost:8080/service1");

            //Instantiate new ServiceHost 
            myServiceHost = new ServiceHost(typeof(TestService.service1), baseAddress);

            //Open myServiceHost
            myServiceHost.Open();
        }

        internal static void StopService()
        {
            //Call StopService from your shutdown logic (i.e. dispose method)
            if (myServiceHost.State != CommunicationState.Closed)
                myServiceHost.Close();
        }
    }

    ################# END MyServiceHost.cs #################
    ################# START App.config or Web.config #################

    <system.serviceModel>
    <services>
         <service name="TestService.service1">
           <endpoint contract="TestService.IService1" binding="wsHttpBinding"/>
         </service>
       </services>
    </system.serviceModel>

    ################# END App.config or Web.config #################

*/
namespace TestService
{
    // You have created a class library to define and implement your WCF service.
    // You will need to add a reference to this library from another project and add 
    // the code to that project to host the service as described below.  Another way
    // to create and host a WCF service is by using the Add New Item, WCF Service 
    // template within an existing project such as a Console Application or a Windows 
    // Application.

    [ServiceContract()]
    public interface IService1
    {
        [OperationContract]
        Patient GetPatient(Int32 index);

        [OperationContract]
        void SetPatient(Int32 index, Patient patient);
    }

    [ServiceBehavior(IncludeExceptionDetailInFaults = true)]
    public class PatientService : IService1
    {
        Patient[] pat = null;

        public PatientService()
        {
            pat = new Patient[3];

            pat[0] = new Patient();
            pat[0].FirstName = "Bob";
            pat[0].LastName = "Chandler";

            pat[1] = new Patient();
            pat[1].FirstName = "Joe";
            pat[1].LastName = "Klink";

            pat[2] = new Patient();
            pat[2].FirstName = "Sally";
            pat[2].LastName = "Wilson";
        }

        public Patient GetPatient(Int32 index)
        {
            if (index <= pat.GetUpperBound(0) && index > -1)
                return pat[index];
            else
                return new Patient();
        }

        public void SetPatient(Int32 index, Patient patient)
        {
            if (index <= pat.GetUpperBound(0) && index > -1)
                pat[index] = patient;
        }
    }

    [DataContract]
    public class Patient
    {
        string firstName;
        string lastName;

        [DataMember]
        public string FirstName
        {
            get { return firstName; }
            set { firstName = value; }
        }

        [DataMember]
        public string LastName
        {
            get { return lastName; }
            set { lastName = value; }
        }
    }
}

服务代码(Form1.cs):

using System;
using System.Windows.Forms;
using System.ServiceModel;

namespace TestService
{
    public partial class Form1 : Form
    {
        bool serviceStarted = false;
        ServiceHost myServiceHost = null;
        NetTcpBinding binding;
        Uri baseAddress = new Uri("net.tcp://localhost:2202/PatientService");

        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            if (serviceStarted)
            {
                myServiceHost.Close();
                serviceStarted = false;
                button1.Text = "Start Service";
            }
            else
            {
                binding = new NetTcpBinding();
                myServiceHost = new ServiceHost(typeof(PatientService), baseAddress);
                myServiceHost.AddServiceEndpoint(typeof(IService1), binding, baseAddress);

                myServiceHost.Open();

                serviceStarted = true;
                button1.Text = "Stop Service";    
            }
        }

        private void button3_Click(object sender, EventArgs e)
        {
            IService1 patientSvc = null;
            EndpointAddress address = new EndpointAddress(baseAddress);
            ChannelFactory<IService1> factory = new ChannelFactory<IService1>(binding, address);
            patientSvc = factory.CreateChannel();

            Patient patient = patientSvc.GetPatient(Convert.ToInt32(textBox1.Text));

            if (patient != null)
            {
                textBox2.Text = patient.FirstName;
                textBox3.Text = patient.LastName;
            }
        }
    }

    static class Program
    {
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form1());
        }
    }
}

这里的代码行:

Patient patient = patientSvc.GetPatient(Convert.ToInt32(textBox1.Text));

是它冻结的地方。同样,这与其他 winform 中的代码相同,并且可以正常工作。只是在服务本身内部使用它时,由于某种原因似乎无法以相同的方式工作??

它给出的错误是这样的:

System.TimeoutException: '发送到 net.tcp://localhost:2202/PatientService 的请求操作未在配置的超时 (00:01:00) 内收到回复。分配给此操作的时间可能是较长超时的一部分。这可能是因为服务仍在处理操作,或者因为服务无法发送回复消息。请考虑增加操作超时(通过将通道/代理转换为 IContextChannel 并设置 OperationTimeout 属性)并确保服务能够连接到客户端。'

有人知道如何让它工作吗?

这是另一个winform代码:

using System;
using System.Windows.Forms;
using System.ServiceModel;
using TestService;

namespace TestClient
{
    public partial class Form1 : Form
    {
        IService1 patientSvc = null;

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            EndpointAddress address = new EndpointAddress(new Uri("net.tcp://localhost:2202/PatientService"));
            NetTcpBinding binding = new NetTcpBinding();
            ChannelFactory<IService1> factory = new ChannelFactory<IService1>(binding, address);
            patientSvc = factory.CreateChannel();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            Patient patient = patientSvc.GetPatient(Convert.ToInt32(textBox1.Text));

            if (patient != null)
            {
                textBox2.Text = patient.FirstName;
                textBox3.Text = patient.LastName;
            }
        }

        private void button2_Click(object sender, EventArgs e)
        {
            Patient patient = new Patient();
            patient.FirstName = textBox2.Text;
            patient.LastName = textBox3.Text;

            patientSvc.SetPatient(Convert.ToInt32(textBox1.Text), patient);
        }
    }
}

TestClient 代码(Program.cs):

using System;
using System.Windows.Forms;

namespace TestClient
{
    static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form1());
        }
    }
}

【问题讨论】:

  • ...is where it freezes up 您可以尝试在button1_Click 的另一个线程中启动您的服务,这样它就不会与 UI 线程共享相同的同步上下文
  • 我收到错误'在创建窗口句柄之前无法在控件上调用 Invoke 或 BeginInvoke。'

标签: c# iis iis-express nettcpbinding servicehost


【解决方案1】:

知道了!感谢@Eser 的提示:)

private void button3_Click(object sender, EventArgs e)
{
    IService1 patientSvc = null;
    EndpointAddress address = new EndpointAddress(baseAddress);
    ChannelFactory<IService1> factory = new ChannelFactory<IService1>(binding, address);
    patientSvc = factory.CreateChannel();

    Thread thread = new Thread(() => sendData(patientSvc));
    thread.Start();            
}

delegate void SetTextCallback(string text, bool isTxt2);

private void SetText(string text, bool isTxt2)
{
    if (isTxt2)
    {
        if (this.textBox2.InvokeRequired)
        {
            SetTextCallback d = new SetTextCallback(SetText);
            textBox2.Invoke(d, new object[] { text, isTxt2 });
        }
        else
        {
            textBox2.Text = text;
        }
    } else {
        if (this.textBox3.InvokeRequired)
        {
            SetTextCallback d = new SetTextCallback(SetText);
            textBox2.Invoke(d, new object[] { text, isTxt2 });
        } else {
            this.textBox3.Text = text;
        }
    }
}

public void sendData(IService1 patientSvc)
{
    Patient patient = patientSvc.GetPatient(Convert.ToInt32(textBox1.Text));

    if (patient != null)
    {
        SetText(patient.FirstName, true);
        SetText(patient.LastName, false);
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-19
    • 1970-01-01
    相关资源
    最近更新 更多