WCF相比于webservice特点是:
支持不同的协议:http tcp IPC MSMQ p2p
支持不同的宿主:网站 控制台 winform WindowsService
双工协议(可在接的同时进行发)
下面来说说WebService的使用第一种方法:
一:在asp.net网站的路由中配置如下代码
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.IgnoreRoute("Remote/{*pathInfo}");//忽略以Remote开头
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
二:服务端
// 注意: 使用“重构”菜单上的“重命名”命令,可以同时更改代码、svc 和配置文件中的类名“CustomService”。
// 注意: 为了启动 WCF 测试客户端以测试此服务,请在解决方案资源管理器中选择 CustomService.svc 或 CustomService.svc.cs,然后开始调试。
public class CustomService : ICustomService
{
public void DoWork()
{
Console.WriteLine("1234");
}
public int Get()
{
return DateTime.Now.Year;
}
public int GetNoAttribuet()
{
return DateTime.Now.Year;
}
public UserInfo GetUser()
{
return new UserInfo()
{
Id = 123,
Name = "董小姐",
Age = 19
};
}
}
ICustomService类
// 注意: 使用“重构”菜单上的“重命名”命令,可以同时更改代码和配置文件中的接口名“ICustomService”。
[ServiceContract]
public interface ICustomService
{
//只有标记OperationContract才能在客户端使用
[OperationContract]
void DoWork();
[OperationContract]
int Get();
int GetNoAttribuet();
[OperationContract]
UserInfo GetUser();
}
userinfo类
// 实体没有无参数构造 需要添加DataContract
//类上面有DataContractAttribute,那么元素需要[DataMember],否则不可见
[DataContractAttribute]
public class UserInfo
{
public UserInfo()
{ }
[DataMember]
public int Id { get; set; }
[DataMember]
public string Name { get; set; }
public int Age { get; set; }
}
下面来说说WebService的使用第二种方法:
引入命名空间:using System.ServiceModel;
//ServiceHost对象
List<ServiceHost> hosts = new List<ServiceHost>()
{
//MathService和CalculatorService相当于上面的CustomService,
new ServiceHost(typeof(MathService)),
new ServiceHost(typeof(CalculatorService))
};
foreach (var host in hosts)
{
host.Opening += (s, e) => Console.WriteLine($"{host.GetType().Name} 准备打开");
host.Opened += (s, e) => Console.WriteLine($"{host.GetType().Name} 已经正常打开");
host.Closing += (s, e) => Console.WriteLine($"{host.GetType().Name} 准备关闭");
host.Closed += (s, e) => Console.WriteLine($"{host.GetType().Name} 准备关闭");
host.Open();
}
Console.WriteLine("输入任何字符,就停止");
Console.Read();
foreach (var host in hosts)
{
host.Close();
}
Console.Read();
配置文件加入下面一段才能使用
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="MathServicebehavior">
<serviceDebug httpHelpPageEnabled="false"/>
<serviceMetadata httpGetEnabled="false"/>
<serviceTimeouts transactionTimeout="00:10:00"/>
<serviceThrottling maxConcurrentCalls="1000" maxConcurrentInstances="1000" maxConcurrentSessions="1000"/>
</behavior>
<behavior name="CalculatorServicebehavior">
<serviceDebug httpHelpPageEnabled="false"/>
<serviceMetadata httpGetEnabled="false"/>
<serviceTimeouts transactionTimeout="00:10:00"/>
<serviceThrottling maxConcurrentCalls="1000" maxConcurrentInstances="1000" maxConcurrentSessions="1000"/>
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<netTcpBinding>
<binding name="tcpbinding">
<security mode="None">
<transport clientCredentialType="None" protectionLevel="None"/>
</security>
</binding>
</netTcpBinding>
</bindings>
<services>
<service name="SOA.WCF.Service.CalculatorService" behaviorConfiguration="CalculatorServicebehavior">
<host>
<baseAddresses>
<add baseAddress="net.tcp://localhost:11111/CalculatorService"/>
</baseAddresses>
</host>
<endpoint address="" binding="netTcpBinding" bindingConfiguration="tcpbinding" contract="SOA.WCF.Interface.ICalculatorService"/>
<endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange"/>
</service>
<service name="SOA.WCF.Service.MathService" behaviorConfiguration="MathServicebehavior">
<host>
<baseAddresses>
<add baseAddress="net.tcp://localhost:11111/MathService"/>
</baseAddresses>
</host>
<endpoint address="" binding="netTcpBinding" bindingConfiguration="tcpbinding" contract="SOA.WCF.Interface.IMathService"/>
<endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="MathServicebehavior">
<serviceDebug httpHelpPageEnabled="false"/>
<serviceMetadata httpGetEnabled="false"/>
<serviceTimeouts transactionTimeout="00:10:00"/>
<serviceThrottling maxConcurrentCalls="1000" maxConcurrentInstances="1000" maxConcurrentSessions="1000"/>
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<basicHttpBinding>
<binding name="httpbinding"/>
</basicHttpBinding>
</bindings>
<services>
<service name="SOA.WCF.Service.MathService" behaviorConfiguration="MathServicebehavior">
<host>
<baseAddresses>
<add baseAddress="http://localhost:11113/MathService"/>
</baseAddresses>
</host>
<endpoint address="" binding="basicHttpBinding" bindingConfiguration="httpbinding" contract="SOA.WCF.Interface.IMathService"/>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
</system.serviceModel>
二:客户端
引用服务后如下方式使用
[TestClass]
public class UnitTestWCF
{
[TestMethod]
public void TestMethod1()
{
int i = 3 + 4;
MyWCFTest.CustomServiceClient client = null;
try
{
client = new MyWCFTest.CustomServiceClient();
int iResult = client.Get();
//int iResult2 = client.GetNoAttribuet();
var user = client.GetUser();
client.Close();
}
catch (Exception ex)
{
if (client != null)
client.Abort();//是为了应对网络断掉异常
Console.WriteLine(ex.Message);
}
//using (MyWCFTest.CustomServiceClient client = new MyWCFTest.CustomServiceClient())
//{
// client.DoWork();
// int iResult = client.Get();
// //int iResult2 = client.GetNoAttribuet();
// var user = client.GetUser();
//}
}
}
双工版的服务端:
接口
[ServiceContract(CallbackContract = typeof(ICallBack))]
public interface ICalculatorService
{
[OperationContract(IsOneWay = true)]
void Plus(int x, int y);
}
回调ICallBack
/// <summary>
/// 不需要协议 是个约束,由客户端实现
/// </summary>
public interface ICallBack
{
[OperationContract(IsOneWay = true)]
void Show(int m, int n, int result);
}
public class CalculatorService : ICalculatorService
{
/// <summary>
/// 完成计算,然后去回调
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
public void Plus(int x, int y)
{
int result = x + y;
Thread.Sleep(2000);
ICallBack callBack = OperationContext.Current.GetCallbackChannel<ICallBack>();
callBack.Show(x, y, result);
}
}
使用方式和上面介绍的一样
//ServiceHost对象
List<ServiceHost> hosts = new List<ServiceHost>()
{
new ServiceHost(typeof(MathService)),
new ServiceHost(typeof(CalculatorService))
};
foreach (var host in hosts)
{
host.Opening += (s, e) => Console.WriteLine($"{host.GetType().Name} 准备打开");
host.Opened += (s, e) => Console.WriteLine($"{host.GetType().Name} 已经正常打开");
host.Closing += (s, e) => Console.WriteLine($"{host.GetType().Name} 准备关闭");
host.Closed += (s, e) => Console.WriteLine($"{host.GetType().Name} 准备关闭");
host.Open();
}
Console.WriteLine("输入任何字符,就停止");
Console.Read();
foreach (var host in hosts)
{
host.Close();
}
Console.Read();
双工客户端使用
继承服务端回调函数
public class CustomCallback : MyConsoleWCTTcpDouble.ICalculatorServiceCallback
{
public void Show(int m, int n, int result)
{
Console.WriteLine($"回调:{m}+{n}={result} ThreadId:{Thread.CurrentThread.ManagedThreadId}");
}
}
class Program
{
static void Main(string[] args)
{
MyConsoleWCTTcpDouble.CalculatorServiceClient client = null;
try
{
Console.WriteLine($"双工调用开始 {Thread.CurrentThread.ManagedThreadId}");
InstanceContext callbackInstance = new InstanceContext(new CustomCallback());
client = new MyConsoleWCTTcpDouble.CalculatorServiceClient(callbackInstance);
client.Plus(123, 234);
client.Close();
Console.WriteLine($"双工调用结束 {Thread.CurrentThread.ManagedThreadId}");
}
catch (Exception ex)
{
if (client != null)
client.Abort();
Console.WriteLine(ex.Message);
}
Console.ReadLine();
}
}