1
分成Wcf服务库 和wcf服务应用程序
[ServiceContract] //1.0 标注当前接口为wcf的服务
public interface IService1
{
[OperationContract]//2.0 标注此方法是一个WCF的服务方法,可以被外部调用
string GetData(int value);
[OperationContract]
CompositeType GetDataUsingDataContract(CompositeType composite);
// TODO: 在此添加您的服务操作
}
2 配置文件(这是wcf类库)
<system.serviceModel>
<!-------------------1-->
<services>
<!--3.0service这个节点中的名称必须是服务契约的实现类的完全限定名称 -->命名空间+类名
<service name="WCFLib.Service1">
<host>
<baseAddresses>
<!--4.0 baseAddress表示wcf主机监听的具体url,本质上是被socket来监听的-->
<add baseAddress = "http://localhost:8733/Design_Time_Addresses/WCFLib/Service1/" />
</baseAddresses>
</host>
<!-- Service Endpoints -->
<!-- 除非完全限定,否则地址将与上面提供的基址相关,如果address为空则默认使用baseAddress -->
<!--5.0 contract一定要指定当前服务的接口的完全限定名称-->
<endpoint address="" binding="basicHttpBinding" contract="WCFLib.IService1">
<!--
部署时,应删除或替换下列标识元素,以反映
用来运行所部署服务的标识。删除之后,WCF 将
自动推断相应标识。
-->
<identity>
<dns value="localhost"/>
</identity>
</endpoint>
<!-- Metadata Endpoints -->
<!-- 元数据交换终结点供相应的服务用于向客户端做自我介绍。 -->
<!-- 此终结点不使用安全绑定,应在部署前确保其安全或将其删除-->
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
<!----------------------1-->
<!----------------------2-->
<service name="WCFLib.BizOrder">
<host>
<baseAddresses>
<add baseAddress="http://localhost:8733/Design_Time_Addresses/WCFLib/BizOrder/"/>
</baseAddresses>
</host>
<endpoint address="" binding="basicHttpBinding" contract="WCFLib.IOrder"></endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
<!---------------------2-->
---------------------33333333333
<!--用于约定WCF的统一行为-->(全局设置) 但是 局部大于全局
<behaviors>
<serviceBehaviors>
<behavior>
<!-- 为避免泄漏元数据信息,
请在部署前将以下值设置为 false -->
<serviceMetadata httpGetEnabled="True" httpsGetEnabled="True"/>
<!-- 要接收故障异常详细信息以进行调试,
请将以下值设置为 true。在部署前设置为 false
以避免泄漏异常信息-->
<serviceDebug includeExceptionDetailInFaults="False" />
</behavior>
</serviceBehaviors>
</behaviors>
---------------------------------3----------
</system.serviceModel>
3 wcf 应用程序 IIS托管 端口是随机分配的 所有没有<host> 节点
在客户端添加的时候 用2种方法可以添加
3.1 直接添加服务引用 这种简单(vs帮你操作)
3.2 手动调用(纯手工)
工具--》外部工具--》添加----
命令: C:Program Files (x86)Microsoft SDKsWindowsv7.0ABinSvcUtil.exe
初始目录 : 选择项目目录
勾选 使用输出窗口 提示输入参数
生成后 ---》点击客户端 --在点击工具 --》在输入的参数中 输入 服务在浏览器中显示的路径---》生成2个文件 (outputConfig 和
Service1)
将outputConfig 文件配置中的 <system.serviceModel> </system.serviceModel>节点配置添加到配置文件中就可以删除outputConfig 了
在生成的Sercice1中 需要添加2个命名空间
System.ServiceModel
System.Runtime.Serialization
调用
Service1Client c = new Service1Client();
MessageBox.Show(c.GetData(100));
。
3.3 如果还需要添加服务的话 就添加一个 wcf 服务 比如是Order服务(自动生成2个文件 1个是 Iorder 1个是 Order.svc)
在Iorder 中定义一个方法
【operationContract】
string DoWork()
Order.svc:Iorder 中需要实现这个方法
public string DoWork()
{
return "sadasdas";
}
浏览Order.svc开始服务
根据工具 --添加生成代理类的时候还是会生成上面的outputconfig 和 Order.cs 文件
注意了此时你要将outputconfig 的配置文件迁移到项目的配置文件中可能是 (webconfig 也有可能是 appconfig )
前面已经添加了一个服务 配置 所有你不能全部复制 <system.serviceModel> </system.serviceModel>节点的
选择outputconfig 中
《basicHttpBinding》
<binding>就是这个节点需要复制上面的节点不管<binding/>(复制这个节点 到项目配置文件中)
</basicHttpBinding>
选择
《Cline》
<ednpoin/>(选择这个节点添加到)-----跟目录下的Client下面
《/Client》
4 wcf 服务类库的自托管代码演示
public class 服务托管类
{
static void Main()
{
//1.0 利用代码 自托管WCF服务
/*
* ServiceHost第一个参数:表示要托管的 wcf服务的实现类的Type类型
* 第二个参数:baseAddress表示当前wcf服务监听的url,如果没有填写默认去app.config中查找
*/
using (ServiceHost host = new ServiceHost(typeof(Service1)))
{
//开启主机环境
host.Open();
Console.WriteLine("wcf服务Services1已经启动....");
Console.ReadKey();
}
}
}
5 Wcf 数据方法
5.1 请求响应方法
ServiceReference1.Service1Client c = new ServiceReference1.Service1Client();
MessageBox.Show(c.GetData(300));响应完了才返回
5.2 数据报方法
数据报方法 (IsOneWay = true 方法的返回类型必须是void
在接口中定义
/// <summary>
/// //标记了此方法是一个数据报访问,特点是,客户端调用此方法后马上响应回去,不管此方法要执行多久
/// </summary>
/// <param name="logtxt"></param>
[OperationContract(IsOneWay = true)]
void WriteLog(string logtxt);
在实现类中 (Iservice中)
public void WriteLog(string logtxt)
{
//写日志到数据库或者磁盘上 (很耗时间)
System.Threading.Thread.Sleep(5000);
}
6 Wcf的双工通讯
6.1 添加一个wcf类库
添加一个接口
/// <summary>
/// 1.0 将接口标记成一个双工通讯接口
/// </summary>
[ServiceContract(SessionMode = SessionMode.Required, CallbackContract = typeof(IResult))]
public interface ILogger
{
/// <summary>
/// 3.0 此方法也必须是一个数据报的方法
/// </summary>
/// <param name="logtxt"></param>
[OperationContract(IsOneWay = true)]
void WriteLog(string logtxt);
}
/// <summary>
/// 2.0 接口的名称可以由程序员自行定义
/// </summary>
public interface IResult
{
/// <summary>
/// 2.0.1 特点:此方法必须是一个数据报的方法
/// </summary>
/// <param name="msg"></param>
[OperationContract(IsOneWay = true)]
void WriteResult(string msg);
}
6.2 添加实现接口
public class Logger : ILogger
{
IResult iresult;
/// 4.0 <summary>
/// 构造函数中接收在客户端实现了IResult的子类的对象实例
/// </summary>
public Logger()
{
//获取了客户端的IResult的具体实现类的对象实例
iresult = OperationContext.Current.GetCallbackChannel<IResult>();
}
public void WriteLog(string logtxt)
{
//1.0 接收到数据以后需要5秒钟才能处理完成
System.Threading.Thread.Sleep(5000);
//2.0 通过回调客户端的函数将处理结果响应给客户端
iresult.WriteResult("您的请求已经处理成功,耗时5秒钟");
}
}
在客户端调用的时候
添加服务引用
配置文件中有变化了
<system.serviceModel>
<bindings>
<wsDualHttpBinding>
<binding name="WSDualHttpBinding_ILogger" closeTimeout="00:01:00"
openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard"
maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<reliableSession ordered="true" inactivityTimeout="00:10:00" />
<security mode="Message">
<message clientCredentialType="Windows" negotiateServiceCredential="true"
algorithmSuite="Default" />
</security>
</binding>
</wsDualHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:8733/Design_Time_Addresses/WCF%E5%8F%8C%E5%B7%A5/Logger/"
binding="wsDualHttpBinding" bindingConfiguration="WSDualHttpBinding_ILogger"
contract="ILogger" name="WSDualHttpBinding_ILogger">
<identity>
<userPrincipalName value="ivanybivan" />
</identity>
</endpoint>
</client>
</system.serviceModel>
、、 在生成代理类的时候 wcf服务类库中的接口ILogger 变成了ILoggerCallback 可以在代理类中查看
public class ResultProcessor : ILoggerCallback
{
public void WriteResult(string msg)
{
MessageBox.Show(msg);
}
}
private void button1_Click(object sender, EventArgs e)
{
// 传一个实现了接口的实咧
LoggerClient c = new LoggerClient(new System.ServiceModel.InstanceContext(new ResultProcessor()));
c.WriteLog("这是异常信息");
}
7 Wcf 如果想建个服务开启电脑就可以运行 那么久可以建个 window服务
8 IIS 承载Net.tcp
1 新建一个wcf服务应用程序 WcfNetTcp
2 新建一个WcfLib服务类库WCFLib; 在新建的服务类库中的配置文件中 去掉《host》</host>节点
修改终结点 endpoint节点
address="net.tcp://127.0.0.1/wcfNetTcp2323/Service1.svc" (指向服务应用程序,,wcfNetTcp2323名而已)
binding 的修改方式 : 点击AppConfig右键复制路径---》工具--》wcf服务配置编辑器--》文件--》打开--》配置文件-》 粘贴路径
就打开了wcf相关绑定配置数据--》服务 --》终结点 --》点击第一个空名称 然后选择 netTcpBinding
--》点击文件--》保存 就保存了这次的选择绑定
3 wcfLIb服务类库不能承载在iis上面 所以我们用Wcf服务应用程序来承载
删除WcfNetTcp的契约IService 和 Svc下面的实现类 --》添加WcfLib的引用--修改WcfNetTcp的Service1.svc中
Service="WcfLib.Service1"指向类库的实现类) 并删除CodeBehind="Service1.svc.cs"
4 将服务类库WcfLib中的配置文件迁移到WcfNetTcp服务应用程序中的配置文件中
<services>
<service name="WcfLib.Service1">
<endpoint address="net.tcp://127.0.0.1/wcfNetTcp/Service1.svc"
binding="netTcpBinding" bindingConfiguration="" contract="WcfLib.IService1">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
</services>
5 打开IIS 在默认的网站中--》右击浏览(找到所在的物理文件)---》新建一个文件夹 netTcp--》拷贝路径--》
6 选择vs中的WcfNetTcp程序--》右击发布--》新建一个配置--》使用文件系统--》
在目标位置输入 刚才拷贝的iis路径 D:Net Tcp
et Tcp
7 发布成功后 在默认网站上 --右击--》添加应用程序--》
别名 一定要和 address="net.tcp://127.0.0.1/WcfByNetTCp/Service1.svc" 中的WcfByNetTCp 这个一一模一样
别名: WcfByNetTCp
物理路径 : D:Net Tcp
et Tcp
8 此时建立的是Http
点击新建的那个默认网站 --》右击--》管理网站--》高级设置--在已启用的协议中 改成 http,net.tcp
9 点击该运用程序--》右击--》管理网站--》高级设置--在已启用的协议中 改成 http,net.tcp
10 点击默认网站--》绑定--添加--》类型改成nettcp--》默认信息 808:*
11 控制面板--》程序功能--》打卡或者关闭Window功能 --》在。netFrameWork中http 和非http都选上
12 点击应用程序--》管理应用程序--》浏览 --》点击Service.Svn -->复制路径
13 新建一个客户端调用的 --.添加服务应用 --》 后面的都一样了
9 WcF 事物的用法
契约和实现类写在yiq
using System.Data.SqlClient;
using System.ServiceModel;
[ServiceContract(SessionMode = SessionMode.Required)] //1 设置当前契约的session模式为开启会话绑定
public interface IPig
{
[OperationContract]
[TransactionFlow(TransactionFlowOption.Mandatory)]
void AddDog();
[OperationContract]
[TransactionFlow(TransactionFlowOption.Mandatory)]
void AddPig();
}
/// <summary>
/// 特性说明
/// 1 //定义当前的事物隔离级别为序列化流
/// 2 // 是否自动提交当前session中所有的事物方法
/// 3 //完成操作以后是否释放对象
/// </summary>
[ServiceBehavior(TransactionIsolationLevel = System.Transactions.IsolationLevel.Serializable
, TransactionAutoCompleteOnSessionClose = true
, ReleaseServiceInstanceOnTransactionComplete = true
)]
public class Pig : IPig
{
// TransactionScopeRequired=true:当前的方法在客户端调用的时候必须要存放在TransactionScope中
//TransactionAutoComplete = true :自动提交事物
[OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
public void AddDog()
{
Insert("dog", "DB1");
}
[OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
public void AddPig()
{
throw new Exception("errror");
Insert("Pig", "DB2");
}
void Insert(string context, string dbname)
{
using (SqlConnection conn = new SqlConnection("server=.;database=" + dbname + ";uid=sa;pwd=master;"))
{
conn.Open();
string sql = "insert into TableA(context) values('" + context + "')";
SqlCommand command = new SqlCommand(sql, conn);
command.ExecuteNonQuery();
}
}
}
配置文件
<system.serviceModel>
<services>
<service name="TransLib.Pig">
<host>
<baseAddresses>
<add baseAddress = "http://localhost:8733/Design_Time_Addresses/TransLib/IPig/" />
</baseAddresses>
</host>
<!-- Service Endpoints -->
<!-- 除非完全限定,否则地址将与上面提供的基址相关 -->
<endpoint address="" binding="wsHttpBinding" contract="TransLib.IPig" bindingConfiguration="trans">
<!--
部署时,应删除或替换下列标识元素,以反映
用来运行所部署服务的标识。删除之后,WCF 将
自动推断相应标识。
-->
<identity>
<dns value="localhost"/>
</identity>
</endpoint>
<!-- Metadata Endpoints -->
<!-- 元数据交换终结点供相应的服务用于向客户端做自我介绍。 -->
<!-- 此终结点不使用安全绑定,应在部署前确保其安全或将其删除 -->
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior>
<!-- 为避免泄漏元数据信息,
请在部署前将以下值设置为 false -->
<serviceMetadata httpGetEnabled="True"/>
<!-- 要接收故障异常详细信息以进行调试,
请将以下值设置为 true。在部署前设置为 false
以避免泄漏异常信息 -->
<serviceDebug includeExceptionDetailInFaults="False" />
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<wsHttpBinding>
<binding name="trans" transactionFlow="True"></binding>
</wsHttpBinding>
</bindings>
</system.serviceModel>
在客户端调用的时候
public static void Main()
{
ServiceReference1.PigClient c = new ServiceReference1.PigClient();
using (System.Transactions.TransactionScope scop = new System.Transactions.TransactionScope())
{
try
{
c.AddDog();
c.AddPig();
scop.Complete();
}
catch
{
}
}
Console.WriteLine("执行成功");
Console.ReadKey();
}