用C#基于WCF创建TCP的Service供Client端调用

本文将详细讲解用C#基于WCF创建TCP的Service供Client端调用的详细过程

1):首先创建一个Windows Service的工程

 

2):生成的代码工程结构如下所示

 

3):我们将Service1改名为MainService

 

4): 添加一个Interface来定义Service的契约

4.1):截图如下所示

 

4.2):IOrderService.cs的代码如下所示

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using System.Threading.Tasks;

namespace EricSunService
{
    [ServiceContract]
    interface IOrderService
    {
        [OperationContract]
        [FaultContract(typeof(ServiceFault))]
        AccountLoginResponse AccountLogin(AccountLoginRequest request);

        [OperationContract]
        [FaultContract(typeof(ServiceFault))]
        AccountTopUpResponse AccountTopUp(AccountTopUpRequest request);
    }

    [DataContract]
    public class ServiceFault
    {
        [DataMember]
        public string CorrelationId { get; set; }
        [DataMember]
        public string Message { get; set; }
        [DataMember]
        public string Address { get; set; }
    }
}
View Code

 

5):然后添加其他的类实现对应的Service,并且实现对Service的Host

5.1):最终的代码工程截图如下所示(这里的EricSunData工程是用于数据类型的定义,为了更好的逻辑结构分层,这里我们主要以AccountLogin.cs中所实现的OrderService进行讲解)

 

5.2):AccountLogin.cs的代码如下所示(实现IOrderService中的部分接口)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using System.Threading.Tasks;

namespace EricSunService
{
    public partial class OrderService : IOrderService
    {
        public AccountLoginResponse AccountLogin(AccountLoginRequest request)
        { 
            // do some logic with account info
            AccountLoginResponse loginResponse = new AccountLoginResponse() { AccountBalance = 10000000.00, Status = new AccountLoginStatus() };
            return loginResponse;
        }
    }


    [DataContract]
    public class AccountLoginRequest
    {
        [DataMember]
        public string Name { get; set; }
        [DataMember]
        public string Password { get; set; }
    }

    [DataContract]
    public class AccountLoginResponse
    {
        [DataMember]
        public double AccountBalance { get; set; }
        [DataMember]
        public AccountLoginStatus Status { get; set; }
    }

    public enum AccountLoginStatus
    {
        NoError = 0,
        InvalidAccountInfo // Invalid Account Info
    }
}
View Code

 

5.3):MainService的代码如下所示 (进行对Service的Host)

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceModel;
using System.ServiceProcess;
using System.Text;
using System.Threading.Tasks;

namespace EricSunService
{
    public partial class MainService : ServiceBase
    {
        private ServiceHost _orderService;

        public MainService()
        {
            InitializeComponent();
        }

        protected override void OnStart(string[] args)
        {
            _orderService = new ServiceHost(typeof(OrderService));
            _orderService.Open();
        }

        protected override void OnStop()
        {
            _orderService.Close();
        }
    }
}
View Code

 

5.4):Program.cs的代码如下所示 (.exe运行时主入口)

using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.ServiceProcess;
using System.Text;
using System.Threading.Tasks;

namespace EricSunService
{
    static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        static void Main()
        {
#if DEBUG
            ServiceHost host = new ServiceHost(typeof(OrderService));
            host.Open();
            System.Threading.Thread.Sleep(System.Threading.Timeout.Infinite);
#else
            ServiceBase[] ServicesToRun;
            ServicesToRun = new ServiceBase[] 
            { 
                new MainService() 
            };
            ServiceBase.Run(ServicesToRun);
#endif
        }
    }
}
View Code

 

6):运行Service时的可能错误以及App.config的配置

6.1):当我们build真个solution之后,到对应的debug目录去运行对应的EricSunService.exe文件时,有可能会出现如下错误,为了解决如下的错误才有了5.4中写法

 

6.2):App.config文件的配置信息,是对WCF框架下暴露Service的endpoint(ABC)的一个详细配置

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <startup> 
      <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
  </startup>
  
  <system.serviceModel>
    <behaviors>
      <serviceBehaviors>
        <behavior name="OrderServiceBehavior">
          <serviceMetadata httpGetEnabled="false" />
          <serviceDebug />
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <services>
      <service behaviorConfiguration="OrderServiceBehavior" name="EricSunService.OrderService">
        <host>
          <baseAddresses>
            <add baseAddress="net.tcp://localhost:3434/" />
          </baseAddresses>
        </host>
        <endpoint address="" binding="netTcpBinding" bindingConfiguration="NetTcpBindingConfig" contract="EricSunService.IOrderService"/>
        <endpoint address="mex" binding="mexTcpBinding" bindingConfiguration="" contract="IMetadataExchange" />
      </service>
    </services>
    <bindings>
      <netTcpBinding>
        <binding name="NetTcpBindingConfig">
          <security mode="None" />
        </binding>
      </netTcpBinding>
    </bindings>
  </system.serviceModel>

</configuration>
View Code

 

7):创建一个Asp.Net MVC 的工程作为Client端去调用所提供的Service,之后是添加对OrderService的引用,如下图所示

 

8):在EricSunService.exe运行起来的状态下,去update此OrderServiceReference,如下图所示

 

9):点击Show All Files之后会看到如下详细的工程文件信息

 

10):同时我们发现了如下图的错误信息

 

11):为了解决这个错误信息,请按下图的步骤进行操作

11.1):鼠标右键点击OrderServiceReference后选择Config Service Reference

 

11.2):取消对Reuse types in referenced assemblies的勾选

 

11.3):点击上图中的OK按钮之后,生成了Service所对应Data的详细信息,如下图所示

 

11.4):最终的工程结构如下图所示

 

12):Service的引用添加完毕之后,就可以对Service进行调用了,我们这里选择的是ChannelFactory的方式,详细代码如下所示

12.1):OrderServiceClientFactory.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.Web;
using EricSunWeb.OrderServiceReference;

namespace EricSunWeb.Business
{
    public static class OrderServiceClientFactory
    {
        private static readonly object CRITICAL_SECTION = new object();
        private static ChannelFactory<IOrderServiceChannel> s_ChannelFactory = null;

        public static IOrderServiceChannel CreateClient()
        {
            if (s_ChannelFactory == null || s_ChannelFactory.State == CommunicationState.Faulted)
            {
                lock (CRITICAL_SECTION)
                {
                    if (s_ChannelFactory == null)
                    {
                        s_ChannelFactory = new ChannelFactory<IOrderServiceChannel>("NetTcpBinding_IOrderService");
                    }
                    else if (s_ChannelFactory.State == CommunicationState.Faulted)
                    {
                        s_ChannelFactory.Abort();
                        s_ChannelFactory = new ChannelFactory<IOrderServiceChannel>("NetTcpBinding_IOrderService");
                    }
                }
            }

            return s_ChannelFactory.CreateChannel();
        }
    }
}
View Code

 

12.2):OrderManager.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using EricSunWeb.OrderServiceReference;

namespace EricSunWeb.Business
{
    public class OrderManager
    {
        public void AccountLogin(string name, string password)
        {
            var request = new AccountLoginRequest
            {
                Name = name,
                Password = password
            };

            AccountLoginResponse response = null;
            var client = OrderServiceClientFactory.CreateClient();
            response = client.AccountLogin(request);

            if (response.Status == AccountLoginStatus.NoError)
            {

            }
            else
            { 
                
            }
        }
    }
}
View Code

 

12.3):OrderController.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using EricSunWeb.Business;
using EricSunWeb.OrderServiceReference;

namespace EricSunWeb.Controllers
{
    public class OrderController : Controller
    {
        //
        // GET: /Order/

        public ActionResult Index()
        {
            new OrderManager().AccountLogin("EricSun", "password");
            return View();
        }

    }
}
View Code

 

OK,整个过程就这样结束了。

 

 

 

 

 

posted @ 2014-05-30 11:13  Eric Sun  阅读(6143)  评论(1编辑  收藏  举报