Windows Communication Foundation(WCF)是由微软开发的一系列支持数据通信的应用程序框架,可以翻译为Windows 通讯开发平台。
整合了原有的windows通讯的 .net Remoting,WebService,Socket的机制,并融合有HTTP和FTP的相关技术。
是Windows平台上开发分布式应用最佳的实践方式。
简单的归结为四大部分
1>.网络服务的协议,即用什么网络协议开放客户端接入。
2>.业务服务的协议,即声明服务提供哪些业务。
3>.数据类型声明,即对客户端与服务器端通信的数据部分进行一致化。
4>.传输安全性相关的定义。
它是.NET框架的一部分,由 .NET Framework3.0 开始引入,与Windows Presentation Foundation及Windows Workflow Foundation并行为新一代 Windows操作系统以及 WinFX 的三个重大应用程序开发类库。在 .NET Framework2.0 以及前版本中,微软发展了 Web Service(SOAP with HTTP communication),.NET Remoting (TCP/HTTP/Pipeline communication) 以及基础的 Winsock 等通信支持。由于各个通信方法的设计方法不同,而且彼此之间也有相互的重叠性,对于开发人员来说,不同的选择会有不同的程序设计模型,而且必须要重新学习,让开发人员在使用中有许多不便。同时,面向服务架构(Service-Oriented Architecture) 也开始盛行于软件工业中,因此微软重新查看了这些通信方法,并设计了一个统一的程序开发模型,对于数据通信提供了最基本最有弹性的支持,这就是 Windows Communication Foundation。
概念
WCF 由于集合了几乎由.NET Framework提供的所有的通信方法,因此学习曲线比较陡峭,开发人员必须要针对各个部份的内涵做深入的了解,才能够操控 WCF 来开发应用程序。
通信双方的沟通方式,由合约来订定。通信双方所遵循的通信方法,由协议绑定来订定。通信期间的安全性,由双方约定的安全性层次来订定。
契约
WCF 的基本概念是以契约(Contract) 来定义双方沟通的协议,合约必须要以接口的方式来体现,而实际的服务代码必须要由这些合约接口派生并实现。合约分成了四种:数据契约(Data Contract),订定双方沟通时的数据格式。服务契约(Service Contract),订定服务的定义。操作契约(Operation Contract),订定服务提供的方法。消息契约(Message Contract),订定在通信期间改写消息内容的规范。一个 WCF 中的契约,就如同下列代码所示:
using System;
using System.ServiceModel;
namespace Microsoft.ServiceModel.Samples
{
[ServiceContract(Namespace = "http://Microsoft.ServiceModel.Samples")] // 服务契约
public interface ICalculator
{
[OperationContract] // 操作契约
double Add(double n1, double n2);
[OperationContract] //操作契约
double Subtract(double n1, double n2);
[OperationContract] // 操作契约
double Multiply(double n1, double n2);
[OperationContract] //操作契约
double Divide(double n1, double n2);
}
}
协议绑定
由于 WCF 支持了HTTP,TCP,Named Pipe,MSMQ,Peer-To-Peer TCP 等协议,而 HTTP 又分为基本 HTTP 支持 (BasicHttpBinding) 以及 WS-HTTP 支持 (WsHttpBinding),而 TCP 亦支持 NetTcpBinding,NetPeerTcpBinding 等通信方式,因此,双方必须要统一通信的协议,并且也要在编码以及格式上要有所一致。一个设置通信协议绑定的示例如下:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<!-- 设定服务系统的资讯 -->
<services>
<service name=" CalculatorService" >
<endpoint address="" binding="wsHttpBinding" bindingConfiguration="Binding1" contract="ICalculator" />
</service>
</services>
<!-- 设定通讯协定系统的资讯 -->
<bindings>
<wsHttpBinding>
<binding name="Binding1">
</binding>
</wsHttpBinding>
</bindings>
</system.serviceModel>
</configuration>
虽然 WCF 也可以使用SOAP做通信格式,但它和以往的ASP. NETXML Web Services不同,因此有部分技术文章中,会将 ASP. NET 的 XML Web Services 称为ASMX Service。WCF 的服务可以挂载于 Console Application,Windows Application,IIS (ASP. NET) Application,Windows Service以及Windows Activation Services中,但大多都会挂在 Windows Service。
安全性层次
WCF 实现上已经支持了传输层次安全性 (Transport-level security) 以及消息层次安全性 (Message-level security) 两种。传输层次安全性:在数据传输时期加密,例如 SSL。消息层次安全性:在数据处理时就加密,例如使用数字签名,散列或是使用密钥加密法等。
客户端
对于 WCF 的客户端来说,WCF 服务就像是一个 Web Service 一样,在 Visual Studio 2008 中,所有 WCF 服务的连接都是由客户端的 服务代理(WCF Service Proxy) 来运行,开发人员不用花费太多心思在通信上,而 WCF Service Proxy 在 Visual Studio 中被称为服务引用(Service Reference)。在 Visual Studio 中加入 WCF 的服务引用时,Visual Studio 会自动帮开发人员做掉一些必要工作(例如组态创建以及产生 Service Proxy 等),开发人员只需要在代码中取用 WCF Service Proxy 对象即可。
WCF的优势
在David Chappell所撰的《Introducing Windows Communication Foundation》一文中,用了一个活鲜鲜的例子,来说明WCF的优势所在。假定我们要为一家汽车租赁公司开发一个新的应用程序,用于租车预约服务。该租车预约服务会被多种应用程序访问,包括呼叫中心(Call Center),基于J2EE的租车预约服务以及合作伙伴的应用程序(Partner Application)。从功能的角度来看,WCF完全可以看作是ASMX,.Net Remoting,Enterprise Service,WSE,MSMQ等技术的并集。(注:这种说法仅仅是从功能的角度。事实上WCF远非简单的并集这样简单,它是真正面向服务的产品,它已经改变了通常的开发模式。)因此,对于上述汽车预约服务系统的例子,利用WCF,就可以解决包括安全、可信赖、互操作、跨平台通信等等需求。开发者再不用去分别了解.Net Remoting,ASMX等各种技术了。概括地说,WCF具有如下的优势:
1、统一性
前面已经叙述,WCF是对于ASMX,.Net Remoting,Enterprise Service,WSE,MSMQ等技术的整合。由于WCF完全是由托管代码编写,因此开发WCF的应用程序与开发其它的.Net应用程序没
有太大的区别,我们仍然可以像创建面向对象的应用程序那样,利用WCF来创建面向服务的应用程序。
2、互操作性
由于WCF最基本的通信机制是SOAP(Simple Object Access Protocol 简易对象访问协议),这就保证了系统之间的互操作性,即使是运行不同的上下文中。这种通信可以是基于.Net到.Net间的通信,如下图所示:
可以跨进程、跨机器甚至于跨平台的通信,只要支持标准的Web Service,例如J2EE应用服务器(如WebSphere,WebLogic)。应用程序可以运行在Windows操作系统下,也可以运行在其他的操作系统,如Sun Solaris,HP Unix,Linux等等。如下图所示:
3、安全与可信赖
WS-Security,WS-Trust和WS-SecureConversation均被添加到SOAP消息中,以用于用户认证,数据完整性验证,数据隐私等多种安全因素。
在SOAP 的header中增加了WS-ReliableMessaging允许可信赖的端对端通信。而建立在WS-Coordination和WS- AtomicTransaction之上的基于SOAP格式交换的信息,则支持两阶段的事务提交(two-phase commit transactions)。上述的多种WS-Policy在WCF中都给与了支持。对于Messaging而言,SOAP是Web Service的基本协议,它包含了消息头(header)和消息体(body)。在消息头中,定义了WS-Addressing用于定位SOAP消息的地址信息,同时还包含了MTOM(消息传输优化机制,Message Transmission Optimization Mechanism)。
4、兼容性
WCF充分的考虑到了与旧有系统的兼容性。安装WCF并不会影响原有的技术如ASMX和.Net Remoting。即使对于WCF和ASMX而言,虽然两者都使用了SOAP,但基于WCF开发的应用程序,仍然可以直接与ASMX进行交互。
在c#网站项目中添加WCF服务
WCF 的服务挂载于IIS (ASP. NET) Application
Visual Studio 2019 找不到WCF服务解决办法
没有看到WCF服务模板,则可能需要安装Visual Studio 的Windows Communication Foundation组件。选择“ 安装更多工具和功能”以打开Visual Studio Installer。选择单个组件选项卡,向下滚动到开发活动,然后选择Windows Communication Foundation。单击修改。
在web项目中添加wcf会自动生成两个文件后手动添加代码(wcf接口和派生类)
WCF 的基本概念是以契约(Contract) 来定义双方沟通的协议,合约必须要以接口的方式来体现,而实际的服务代码必须要由这些合约接口派生并实现
其中wcf服务端(宿主项目)配置文件对于wcf的配置都是IDE自动生成
在浏览器中查看
在测试应用程序中添加WCF服务引用
客户端测试应用程序配置文件对于wcf的配置都是IDE自动生成
调用wcf服务
输出结果
在c#中编写WCF服务
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using System.Threading.Tasks;
namespace WCF.Model
{
[DataContract]
public class Contact
{
[DataMember]
public string Id { get; set; }
[DataMember]
public string Name { get; set; }
[DataMember]
public string PhoneNo { get; set; }
[DataMember]
public string EmailAddress { get; set; }
[DataMember]
public string Address { get; set; }
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.Text;
using System.Threading.Tasks;
using WCF.Model;
namespace WCF.Interface
{
[ServiceContract]//服务契约(Service Contract)
public interface IContactService
{
[OperationContract]//必须标记.操作契约(Operation Contract)
int Add(int a, int b);
[OperationContract]
List<Contact> Select(string id = null);
[OperationContract]
void Insert(Contact contact);
[OperationContract]
void Update(Contact contact);
[OperationContract]
void Delete(string id);
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using WCF.Interface;
using WCF.Model;
namespace WCF.Service
{
public class ContactService : IContactService
{
static List<Contact> contacts;
static int counter = 2;
static ContactService()
{
contacts = new List<Contact>();
contacts.Add(new Contact { Id = "001", Name = "张三", PhoneNo = "0512-12345678", EmailAddress = "zhangsan@gmail.com", Address = "江苏省苏州市星湖街328号" });
contacts.Add(new Contact { Id = "002", Name = "李四", PhoneNo = "0512-23456789", EmailAddress = "lisi@gmail.com", Address = "江苏省苏州市金鸡湖大道328号" });
}
public int Add(int a, int b)
{
return a + b;
}
public void Delete(string id)
{
contacts.Remove(contacts.First(c => c.Id == id));
}
public void Insert(Contact contact)
{
Interlocked.Increment(ref counter);
contact.Id = counter.ToString("D3");
contacts.Add(contact);
}
public List<Contact> Select(string id = null)
{
return (from contact in contacts
where contact.Id == id || string.IsNullOrEmpty(id)
select contact).ToList();
}
public void Update(Contact contact)
{
contacts.Remove(contacts.First(c => c.Id == contact.Id));
contacts.Add(contact);
}
}
}
WCF服务配置
以控制台应用程序做wcf宿主,控制台应用程序配置文件添加wcf配置信息
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8" />
</startup>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="ContactServicebehavior">
<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="WCF.Service.ContactService" behaviorConfiguration="ContactServicebehavior">
<host>
<baseAddresses>
<add baseAddress="net.tcp://localhost:9002/ContactService"/>
</baseAddresses>
</host>
<endpoint address="" binding="netTcpBinding" bindingConfiguration="tcpbinding" contract="WCF.Interface.IContactService"/>
<endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange"/>
</service>
</services>
<!--<behaviors>
<serviceBehaviors>
<behavior name="ContactServicebehavior">
<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="WCF.Service.ContactService" behaviorConfiguration="ContactServicebehavior">
<host>
<baseAddresses>
<add baseAddress="http://localhost:9001/ContactService"/>
</baseAddresses>
</host>
<endpoint address="" binding="basicHttpBinding" bindingConfiguration="httpbinding" contract="WCF.Interface.IContactService"/>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>-->
</system.serviceModel>
</configuration>
关于WCF中的地址和绑定补充:
WCF中支持的传输协议包括HTTP、TCP、Peer network(对等网)、IPC(基于命名管道的内部进程通信)以及MSMQ(微软消息队列)。
每个协议对应一个地址类型:
• HTTP地址:http://localhost:8080/
• TCP地址: net.tcp://localhost:8080/
• IPC地址: net.pipe://localhost/ (适用于跨进程,不能使用于不同机器间)
• MSMQ地址: net.msmq://localhost/
• 对等网地址: net.p2p://localhost/
WCF中提供的绑定有:
• BasicHttpBinding: 最简单的绑定类型,通常用于 Web Services。使用 HTTP 协议,Text/XML 编码方式。
• WSHttpBinding: 比 BasicHttpBinding 更加安全,通常用于 non-duplex 服务通讯。
• WSDualHttpBinding: 和 WSHttpBinding 相比,它支持 duplex 类型的服务。
• WSFederationHttpBinding: 支持 WS-Federation 安全通讯协议。
• NetTcpBinding: 效率最高,安全的跨机器通讯方式。
• NetNamedPipeBinding: 安全、可靠、高效的单机服务通讯方式。
• NetMsmqBinding: 使用消息队列在不同机器间进行通讯。
• NetPeerTcpBinding: 使用 P2P 协议在多机器间通讯。
• MsmqIntegrationBinding: 使用现有的消息队列系统进行跨机器通讯。如 MSMQ。
WCF服务寄宿控制台应用程序
using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.Text;
using System.Threading.Tasks;
using WCF.Service;
namespace Wcf2Host
{
public class WcfServiceInit
{
public static void Process()
{
List<ServiceHost> hosts = new List<ServiceHost>()
{
new ServiceHost(typeof(ContactService))
};
foreach (var host in hosts)
{
host.Opening += (s, e) => Console.WriteLine($"{host.GetType().Name} 准备打开");
host.Opened += (s, e) => Console.WriteLine($"{host.GetType().Name} 已经正常打开");
host.Open();
}
Console.WriteLine("输入任何字符,就停止");
Console.Read();
foreach (var host in hosts)
{
host.Close();
Console.WriteLine("已经停止");
}
Console.Read();
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Wcf2Host
{
class Program
{
static void Main(string[] args)
{
try
{
Console.WriteLine("Wcf2Host...");
WcfServiceInit.Process();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
Console.Read();
}
}
}
WCF服务调用
使用MVC应用程序添加服务引用,用服务基地址net.tcp://localhost:9002/ContactService来添加服务引用,配置文件将自动添加配置信息(添加服务引用前先以管理员权限运行wcf宿主控制台应用程序,将服务挂起)
MVC控制器调用WCF服务
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using WCFModel;
namespace SOAWebApp.Controllers
{
public class WcfController : Controller
{
// GET: Wcf
public ActionResult WcfService1()
{
//using (WcfService1Reference.WcfService1Client client =new WcfService1Reference.WcfService1Client())
//{
// client.DoWork();
// ViewBag.GetString = client.GetString();
// ViewBag.GetUserList = client.GetUserList(0);
//}
WcfService1Reference.WcfService1Client client = null;
try
{
client = new WcfService1Reference.WcfService1Client();
client.DoWork();
ViewBag.GetString = client.GetString();
ViewBag.GetUserList = client.GetUserList(0);
client.Close();
return View();
}
catch (Exception)
{
if (client != null) client.Abort();
throw;
}
}
public ActionResult CRUD()
{
return View();
}
public ActionResult Select()
{
using (WcfService2Reference.ContactServiceClient client = new WcfService2Reference.ContactServiceClient())
{
var a = client.Select(null);
return Json(a, JsonRequestBehavior.AllowGet);
}
}
public ActionResult Insert(Contact contact)
{
Contact contact1 = new Contact()
{
Name = contact.Name,
PhoneNo = contact.PhoneNo,
EmailAddress = contact.EmailAddress,
Address = contact.Address
};
using (WcfService2Reference.ContactServiceClient client = new WcfService2Reference.ContactServiceClient())
{
client.Insert(contact1);
}
return Content("ok");
}
public ActionResult Delete()
{
string strId = Request["strId"];
using (WcfService2Reference.ContactServiceClient client = new WcfService2Reference.ContactServiceClient())
{
client.Delete(strId);
}
return Content("ok");
}
public ActionResult ShowEdit()
{
string id = Request["rowsid"];
using (WcfService2Reference.ContactServiceClient client = new WcfService2Reference.ContactServiceClient())
{
var a = client.Select(id);
return Json(a, JsonRequestBehavior.AllowGet);
}
}
public ActionResult Edit(Contact contact)
{
Contact contact1 = new Contact()
{
Name = contact.Name,
PhoneNo = contact.PhoneNo,
EmailAddress = contact.EmailAddress,
Address = contact.Address
};
using (WcfService2Reference.ContactServiceClient client = new WcfService2Reference.ContactServiceClient())
{
client.Update(contact1);
}
return Content("ok");
}
}
}
MVC视图返回wcf结果
@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Index</title>
<link href="~/Content/themes/default/easyui.css" rel="stylesheet" />
<link href="~/Content/themes/icon.css" rel="stylesheet" />
<script src="~/Scripts/jquery-1.7.1.min.js"></script>
<script src="~/Scripts/jquery.easyui.min.js"></script>
<script src="~/Scripts/easyui-lang-zh_CN.js"></script>
<script src="~/Scripts/datapattern.js"></script>
<script src="~/Scripts/jquery.unobtrusive-ajax.min.js"></script>
<script src="~/Scripts/jquery.validate.min.js"></script>
<script type="text/javascript">
$(function () {
$("#addDiv").css("display", "none");
$("#editDiv").css("display", "none");
loadData();
});
function loadData(pars) {
$('#tt').datagrid({
url: '/Wcf2CRUD/Select',
title: '用户数据表格',
width: 700,
height: 400,
fitColumns: true, //列自适应
nowrap: false,
idField: 'Id',//主键列的列明
loadMsg: '正在加载用户的信息...',
pagination: false,//是否有分页
singleSelect: false,//是否单行选择
pageSize: 10,//页大小,一页多少条数据
pageNumber: 1,//当前页,默认的
pageList: [5, 10, 15],
queryParams: pars,//往后台传递参数
columns: [[//c.UserName, c.UserPass, c.Email, c.RegTime
{ field: 'ck', checkbox: true, align: 'left', width: 50 },
{ field: 'Id', title: '编号', width: 60 },
{ field: 'Name', title: '姓名', width: 80 },
{ field: 'PhoneNo', title: '电话', width: 80 },
{ field: 'EmailAddress', title: '邮箱', width: 120 },
{ field: 'Address', title: '地址', width: 120 }
]],
toolbar: [{
id: 'btnDelete',
text: '删除',
iconCls: 'icon-remove',
handler: function () {
deleteInfo();
}
}, {
id: 'btnAdd',
text: '添加',
iconCls: 'icon-add',
handler: function () {
addInfo();
}
}, {
id: 'btnEidt',
text: '编辑',
iconCls: 'icon-edit',
handler: function () {
showEditInfo();
}
}],
});
}
//删除数据
function deleteInfo() {
var rows = $('#tt').datagrid('getSelections');//获取所选择的行
if (!rows || rows.length == 0) {
//alert("请选择要修改的商品!");
$.messager.alert("提醒", "请选择要删除的记录!", "error");
return;
}
$.messager.confirm("提示", "确定要删除数据吗", function (r) {
if (r) {
//获取要删除的记录的ID值。
var rowsLength = rows.length;
var strId = "";
for (var i = 0; i < rowsLength; i++) {
strId = strId + rows[i].Id + ",";//1,2,3,
}
//去掉最后一个逗号.
strId = strId.substr(0, strId.length - 1);
//将获取的要删除的记录的ID值发送到服务端.
$.post("/Wcf2CRUD/Delete", { "strId": strId }, function (data) {
if (data == "ok") {
$('#tt').datagrid('reload');//加载表格不会跳到第一页。
//清除上次操作的历史的记录。
$('#tt').datagrid('clearSelections')
} else {
$.messager.alert("提醒", "删除记录失败!", "error");
}
});
}
});
}
//添加数据
function addInfo() {
$("#addDiv").css("display", "block");
$('#addDiv').dialog({
title: '添加用户数据',
width: 300,
height: 200,
collapsible: true,
maximizable: true,
resizable: true,
modal: true,
buttons: [{
text: 'Ok',
iconCls: 'icon-ok',
handler: function () {
$("#addForm").submit();//提交表单
}
}, {
text: 'Cancel',
handler: function () {
$('#addDiv').dialog('close');
}
}]
});
}
//完成添加后调用该方法
function afterAdd(data) {
if (data == "ok") {
$('#addDiv').dialog('close');
$('#tt').datagrid('reload');//加载表格不会跳到第一页。
$("#addForm input").val("");//清空表单input标签数据
}
}
//展示一下要修改的数据.
function showEditInfo() {
//判断一下用户是否选择了要修改的数据
var rows = $('#tt').datagrid('getSelections');//获取所选择的行,也只能一行
if (rows.length != 1) {
$.messager.alert("提示", "请选择要修改的数据", "error");
return;
}
//将要修改的数据查询出来,显示到文本框中。
var rowsid = rows[0].Id;//从选中的行拿id
//$.post异步请求
$.post("/Wcf2CRUD/ShowEdit", { "rowsid": rowsid }, function (data) {
$("#txtId").val(data.Id);
$("#txtName").val(data.Name);
$("#txtPhoneNo").val(data.PhoneNo);
$("#txtEmailAddress").val(data.EmailAddress);
$("#txtAddress").val(data.Address);
});
$("#editDiv").css("display", "block");
$('#editDiv').dialog({
title: '编辑用户数据',
width: 300,
height: 200,
collapsible: true,
maximizable: true,
resizable: true,
modal: true,
buttons: [{
text: 'Ok',
iconCls: 'icon-ok',
handler: function () {
$("#editForm").submit();//提交表单
}
}, {
text: 'Cancel',
handler: function () {
$('#editDiv').dialog('close');
}
}]
});
}
//更新以后调用该方法.
function afterEdit(data) {
if (data == "ok") {
$('#editDiv').dialog('close');
$('#tt').datagrid('reload');//加载表格不会跳到第一页。
} else {
$.messager.alert("提示", "修改的数据失败", "error");
}
}
</script>
</head>
<body>
<div>
<table id="tt" style="width: 700px;" title="标题,可以使用代码进行初始化,也可以使用这种属性的方式" iconcls="icon-edit">
</table>
</div>
<!--------------添加数据---------------------->
<div id="addDiv">
@using (Ajax.BeginForm("Insert", "Wcf2CRUD", new { }, new AjaxOptions() { HttpMethod = "post", OnSuccess = "afterAdd" }, new { id = "addForm" }))
{
<table>
<tr><td>姓名</td><td><input type="text" name="Name" /></td></tr>
<tr><td>电话</td><td><input type="password" name="PhoneNo" /></td></tr>
<tr><td>邮箱</td><td><input type="text" name="EmailAddress" /></td></tr>
<tr><td>地址</td><td><input type="text" name="Address" /></td></tr>
</table>
}
</div>
<!--------------修改数据---------------------->
<div id="editDiv">
@using (Ajax.BeginForm("Edit", "Wcf2CRUD", new { }, new AjaxOptions() { HttpMethod = "post", OnSuccess = "afterEdit" }, new { id = "editForm" }))
{
<input type="hidden" name="Id" id="txtId" />
<table>
<tr><td>姓名</td><td><input type="text" name="Name" id="txtName" /></td></tr>
<tr><td>电话</td><td><input type="text" name="PhoneNo" id="txtPhoneNo" /></td></tr>
<tr><td>邮箱</td><td><input type="text" name="EmailAddress" id="txtEmailAddress" /></td></tr>
<tr><td>地址</td><td><input type="text" name="Address" id="txtAddress" /></td></tr>
</table>
}
</div>
</body>
</html>
WCF权限认证多种方式
1 无身份验证
2 windows身份验证
3 用户账号密码
4 证书
5 口令(token)
可以参考
http://www.cnblogs.com/zuowj/p/5021270.html
http://www.cnblogs.com/zuowj/p/5078500.html
WCF通过扩展实现用户名密码认证
WCF双工通信的应用
概述
双工(Duplex)模式的消息交换方式体现在消息交换过程中,参与的双方均可以向对方发送消息。基于双工MEP消息交换可以看成是多个基本模式下(比如请求-回复模式和单项模式)消息交换的组合。双工MEP又具有一些变体,比如典型的订阅-发布模式就可以看成是双工模式的一种表现形式。双工消息交换模式使服务端回调(Callback)客户端操作成为可能。
在Wcf中不是所有的绑定协议都支持回调操作,BasicHttpBinding,WSHttpBinding绑定协议不支持回调操作;NetTcpBinding和NetNamedPipeBinding绑定支持回调操作;WSDualHttpBinding绑定是通过设置两个HTTP信道来支持双向通信,所以它也支持回调操作。
两种典型的双工MEP
1.请求过程中的回调
这是一种比较典型的双工消息交换模式的表现形式,客户端在进行服务调用的时候,附加上一个回调对象;服务在对处理该处理中,通过客户端附加的回调对象(实际上是调用回调服务的代理对象)回调客户端的操作(该操作在客户端执行)。整个消息交换的过程实际上由两个基本的消息交换构成,其一是客户端正常的服务请求,其二则是服务端对客户端的回调。两者可以采用请求-回复模式,也可以采用单向(One-way)的MEP进行消息交换。下图描述了这样的过程,服务调用和回调都采用请求-回复MEP。
2.订阅-发布
订阅-发布模式是双工模式的一个典型的变体。在这个模式下,消息交换的双方变成了订阅者和发布者,若干订阅者就某个主题向发布者申请订阅,发布者将所有的订阅者保存在一个订阅者列表中,在某个时刻将主题发送给该主题的所有订阅者。实际上基于订阅-发布模式的消息交换也可以看成是两个基本模式下消息交换的组合,申请订阅是一个单向模式的消息交换(如果订阅者行为得到订阅的回馈,该消息交换也可以采用请求-回复模式);而主题发布也是一个基于单向模式的消息交换过程。订阅-发布消息交换模式如下图所示。
示例
创建一个简单的Wcf通信服务,包括使使用NetTcpBinding实现双工通信。
服务端wcf服务接口和回调接口
服务端wcf服务+回调绑定
服务端wcf服务配置
客户端添加服务引用,同上上上。。。
客户端对服务端回调函数的实现
客户端调用服务,服务端将会通过回调执行客户端回调函数,实现简单双工通讯