程序之间的通信有很多方法,API,Socket,共享路径的配置文档等等,
Windows Communication Foundation(WCF)是由微软开发的一系列支持数据通信的应用程序框架,可以翻译为Windows 通讯开发平台。
整合了原有的windows通讯的 .net Remoting,WebService,Socket的机制,并融合有HTTP和FTP的相关技术。
简单的归结为四大部分
1>.网络服务的协议,即用什么网络协议开放客户端接入。
2>.业务服务的协议,即声明服务提供哪些业务。
3>.数据类型声明,即对客户端与服务器端通信的数据部分进行一致化。
4>.传输安全性相关的定义。
下面直接看一个例子:(服务端)
1.定义一个WCF接口名称未Ichangeline
// 注意: 使用“重构”菜单上的“重命名”命令,可以同时更改代码和配置文件中的接口名“IStaffLoginCheckService”。
[ServiceContract] //服务协定定义
public interface IChangeline
{
[OperationContract] // 操作服务定义
string EsopCheckOk();
[OperationContract]
string HelloWorld();
}
2.定义一个类实现接口名称Changeline
// 注意: 使用“重构”菜单上的“重命名”命令,可以同时更改代码和配置文件中的类名“StaffLoginCheckService”。
[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Single, InstanceContextMode = InstanceContextMode.Single)]
public class Changeline : IChangeline
{
public string HelloWorld()
{
string result = "123456";
return result;
}
}
3.开通WCF所需要的服务,也可以从VS直接添加WCF服务
#region 启动WCF服务
private void OpenWcfService()
{
try
{
var changeline = new Changeline(bendview);
host = new ServiceHost(changeline, new Uri("http://localhost:8734/MyService/"));
//这是我们服务的地址
host.AddServiceEndpoint(typeof(IChangeline), new BasicHttpBinding(), string.Empty);
host.Description.Behaviors.Add(new ServiceMetadataBehavior { HttpGetEnabled = true });
//mex元数据的地址
host.AddServiceEndpoint(typeof(IMetadataExchange), MetadataExchangeBindings.CreateMexHttpBinding(),
"mex");
host.Open();
var port = "8734"; //获取端口号
var inname = "Changeline"; //打开端口号的名称
var str = " netsh advfirewall firewall add rule name=" + inname +
" dir=in action=allow protocol=TCP localport= " + port;
var pro = new Process(); //实例化进程
pro.StartInfo.FileName = "cmd.exe"; //设置要运行的程序文件
pro.StartInfo.UseShellExecute = false; //是否使用操作系统shell程序启动
pro.StartInfo.RedirectStandardInput = true; //是否接受来自应用程序的调用
pro.StartInfo.RedirectStandardOutput = true; //是否接受来自应用程序的输出信息
pro.StartInfo.RedirectStandardError = true; //是否接受重定向错误信息
pro.StartInfo.CreateNoWindow = true; //不显示窗口信息
pro.Start(); //启动程序
//向cmd窗口发送输入信息
pro.StandardInput.WriteLine(str + "&exit");
pro.StandardInput.AutoFlush = true;
pro.WaitForExit(); //等待程序运行完退出程序
pro.Close(); //关闭进程
}
catch (Exception ex)
{
Tool.Log.Error("WCF开起失败:" + ex.Message);
}
CheckWCFServerTh = new Thread(WCF_HostCheck);
CheckWCFServerTh.IsBackground = true;
CheckWCFServerTh.Start();
}
void WCF_HostCheck(object o)
{
//Closed 指示通信对象已关闭,且不再可用。
//Closing 指示通信对象正转换到 Closed 状态。
//Created 指示通信对象已实例化且可配置,但尚未打开或无法使用。
//Faulted 指示通信对象发生错误,无法恢复且不再可用。
//Opened 指示通信对象目前已打开,且随时可供使用。
//Opening 指示通信对象正从 Created 状态转换到 Opened 状态。
while (true)
{
try
{
if (!(host.State == CommunicationState.Opened || host.State == CommunicationState.Opening))
{
var changeline = new Changeline(bendview);
host = new ServiceHost(changeline, new Uri("http://localhost:8734/MyService/"));
//这是我们服务的地址
host.AddServiceEndpoint(typeof(IChangeline), new BasicHttpBinding(), string.Empty);
host.Description.Behaviors.Add(new ServiceMetadataBehavior { HttpGetEnabled = true });
//mex元数据的地址
host.AddServiceEndpoint(typeof(IMetadataExchange), MetadataExchangeBindings.CreateMexHttpBinding(),
"mex");
host.Open();
var port = "8734"; //获取端口号
var inname = "Changeline"; //打开端口号的名称
var str = " netsh advfirewall firewall add rule name=" + inname +
" dir=in action=allow protocol=TCP localport= " + port;
var pro = new Process(); //实例化进程
pro.StartInfo.FileName = "cmd.exe"; //设置要运行的程序文件
pro.StartInfo.UseShellExecute = false; //是否使用操作系统shell程序启动
pro.StartInfo.RedirectStandardInput = true; //是否接受来自应用程序的调用
pro.StartInfo.RedirectStandardOutput = true; //是否接受来自应用程序的输出信息
pro.StartInfo.RedirectStandardError = true; //是否接受重定向错误信息
pro.StartInfo.CreateNoWindow = true; //不显示窗口信息
pro.Start(); //启动程序
//向cmd窗口发送输入信息
pro.StandardInput.WriteLine(str + "&exit");
pro.StandardInput.AutoFlush = true;
pro.WaitForExit(); //等待程序运行完退出程序
pro.Close(); //关闭进程
}
}
catch (Exception ex)
{
Tool.Log.Error("WCF开起失败:" + ex.Message);
}
Thread.Sleep(3000);
}
}
#endregion
二.客户端的程序
1.配置好通道工厂,为客户端创立独立通道,为获取接口配置程序可以创建一个类(WcfChannelFactory)
/// <summary>
/// 使用ChannelFactory为wcf客户端创建独立通道
/// </summary>
public class WcfChannelFactory
{
public WcfChannelFactory()
{
}
/// <summary>
/// 执行方法 WSHttpBinding
/// </summary>
/// <typeparam name="T">服务接口</typeparam>
/// <param name="uri">wcf地址</param>
/// <param name="methodName">方法名</param>
/// <param name="args">参数列表</param>
public static object ExecuteMetod<T>(string uri, string methodName, params object[] args)
{
//BasicHttpBinding binding = new BasicHttpBinding(); //出现异常:远程服务器返回错误: (415) Cannot process the message because the content type 'text/xml; charset=utf-8' was not the expected type 'application/soap+xml; charset=utf-8'.。
WSHttpBinding binding = new WSHttpBinding();
EndpointAddress endpoint = new EndpointAddress(uri);
using (ChannelFactory<T> channelFactory = new ChannelFactory<T>(binding, endpoint))
{
T instance = channelFactory.CreateChannel();
using (instance as IDisposable)
{
try
{
Type type = typeof(T);
MethodInfo mi = type.GetMethod(methodName);
return mi.Invoke(instance, args);
}
catch (TimeoutException)
{
(instance as ICommunicationObject).Abort();
throw;
}
catch (CommunicationException)
{
(instance as ICommunicationObject).Abort();
throw;
}
catch (Exception vErr)
{
(instance as ICommunicationObject).Abort();
throw;
}
}
}
}
//nettcpbinding 绑定方式
public static object ExecuteMethod<T>(string pUrl, string pMethodName,params object[] pParams)
{
EndpointAddress address = new EndpointAddress(pUrl);
Binding bindinginstance = null;
BasicHttpBinding ws = new BasicHttpBinding();
ws.MaxReceivedMessageSize = 20971520;
bindinginstance = ws;
using (ChannelFactory<T> channel = new ChannelFactory<T>(bindinginstance, address))
{
T instance = channel.CreateChannel();
using (instance as IDisposable)
{
try
{
Type type = typeof(T);
MethodInfo mi = type.GetMethod(pMethodName);
return mi.Invoke(instance, pParams);
}
catch (TimeoutException)
{
(instance as ICommunicationObject).Abort();
throw;
}
catch (CommunicationException)
{
(instance as ICommunicationObject).Abort();
throw;
}
catch (Exception vErr)
{
(instance as ICommunicationObject).Abort();
throw;
}
}
}
}
}
2.调用WcfChannelFactory,获取接口数据
调用时需要把服务端开的接口添加到本程序中,
public void Statedeal()
{
try
{
string result = WcfChannelFactory.ExecuteMethod<IChangeline>("http://localhost:8734/MyService/", "EsopCheckOk").ToString();
MessageBox.Show(result.ToString());
}
catch(Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
此时整个的服务端与客户端都可以实现了,如果客户端程序中也含有wcf服务程序(也会发布WCF服务,也作为服务端),并且接口名称与服务端(本客户端的服务端)的接口名称相同,那就必须保证服务端提供的接口名称与客户端定义的接口名称不同,或者相同名称在不同的程序集下。