本文将详细讲解用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; }
}
}
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
}
}
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();
}
}
}
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
}
}
}
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>
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();
}
}
}
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
{}
}
}
}
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();
}}
}
OK,整个过程就这样结束了。
用C#基于WCF创建TCP的Service供Client端调用