[源码下载]
稳扎稳打Silverlight(22) - 2.0通信之调用WCF服务, 对传输信息做加密
作者:webabcd
介绍
Silverlight 2.0 调用 WCF 服务,对客户端与服务端传输的消息做加密
在 Visual Studio 2008 中使用"添加服务引用"会自动生成代理类。只支持BasicHttpBinding
在线DEMO
http://www.cnblogs.com/webabcd/archive/2008/10/09/1307486.html
示例
clientaccesspolicy.xml
<?xml version="1.0" encoding="utf-8" ?>
<access-policy>
<cross-domain-access>
<policy>
<allow-from http-request-headers="*">
<domain uri="*" />
</allow-from>
<grant-to>
<resource path="/" include-subpaths="true" />
</grant-to>
</policy>
</cross-domain-access>
</access-policy>
<!--
System.Net 命名空间 和 System.Net.Sockets 命名空间的跨域调用,需要在目标域的根目录下配置策略文件
Image 控件 和 MediaElement 控件所访问的跨域地址,不受策略文件的限制
HTTP 调用 仅支持 GET 和 POST ,只有 200(确定) 和 404(未找到) 状态代码可用
同域:同一子域、协议和端口。不符合以上任一条件则为跨域
Silverlight 与 HTTP/HTTPS 的所有通信均为异步
关于策略文件详见文档
-->
<access-policy>
<cross-domain-access>
<policy>
<allow-from http-request-headers="*">
<domain uri="*" />
</allow-from>
<grant-to>
<resource path="/" include-subpaths="true" />
</grant-to>
</policy>
</cross-domain-access>
</access-policy>
<!--
System.Net 命名空间 和 System.Net.Sockets 命名空间的跨域调用,需要在目标域的根目录下配置策略文件
Image 控件 和 MediaElement 控件所访问的跨域地址,不受策略文件的限制
HTTP 调用 仅支持 GET 和 POST ,只有 200(确定) 和 404(未找到) 状态代码可用
同域:同一子域、协议和端口。不符合以上任一条件则为跨域
Silverlight 与 HTTP/HTTPS 的所有通信均为异步
关于策略文件详见文档
-->
1、调用 WCF 服务
WCFService.cs(WCF 服务)
using System;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.Collections.Generic;
using System.Text;
using System.Security.Cryptography;
using System.IO;
/// <summary>
/// 提供 WCF 服务的类
/// </summary>
[ServiceContract]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class WCFService
{
/// <summary>
/// 返回指定的 User 对象(用于演示 Silverlight 调用 WCF 服务)
/// </summary>
/// <param name="name">名字</param>
/// <returns></returns>
[OperationContract]
public User GetUser(string name)
{
return new User { Name = name, DayOfBirth = new DateTime(1980, 2, 14) };
}
}
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.Collections.Generic;
using System.Text;
using System.Security.Cryptography;
using System.IO;
/// <summary>
/// 提供 WCF 服务的类
/// </summary>
[ServiceContract]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class WCFService
{
/// <summary>
/// 返回指定的 User 对象(用于演示 Silverlight 调用 WCF 服务)
/// </summary>
/// <param name="name">名字</param>
/// <returns></returns>
[OperationContract]
public User GetUser(string name)
{
return new User { Name = name, DayOfBirth = new DateTime(1980, 2, 14) };
}
}
WCF.xaml
<UserControl x:Class="Silverlight20.Communication.WCF"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<StackPanel HorizontalAlignment="Left" Margin="5">
<TextBlock x:Name="lblMsg" />
</StackPanel>
</UserControl>
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<StackPanel HorizontalAlignment="Left" Margin="5">
<TextBlock x:Name="lblMsg" />
</StackPanel>
</UserControl>
WCF.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Silverlight20.WCFServiceReference;
using System.Threading;
using System.ServiceModel;
namespace Silverlight20.Communication
{
public partial class WCF : UserControl
{
SynchronizationContext _syncContext;
/// <summary>
/// 演示 Silverlight 调用 WCF 服务
/// </summary>
public WCF()
{
InitializeComponent();
// 代理的配置信息在配置文件中,UI线程上的异步调用
Demo();
// 代理的配置信息在程序中指定,UI线程上的异步调用
Demo2();
// 后台线程(非UI线程)上的异步调用)
Demo3();
}
void Demo()
{
/*
* 服务名Client - 系统自动生成的代理类
* 方法名Completed - 调用指定的方法完成后所触发的事件
* 方法名Async(参数1, 参数2 , object 用户标识) - 异步调用指定的方法
* Abort() - 取消调用
*/
WCFServiceClient client = new WCFServiceClient();
client.GetUserCompleted += new EventHandler<GetUserCompletedEventArgs>(client_GetUserCompleted);
client.GetUserAsync("webabcd");
}
void Demo2()
{
/*
* 服务名Client - 其构造函数可以动态地指定代理的配置信息(Silverlight 2.0 调用 WCF 只支持 BasicHttpBinding)
*/
WCFServiceClient client = new WCFServiceClient(new BasicHttpBinding(), new EndpointAddress("http://localhost:3036/WCFService.svc"));
client.GetUserCompleted += new EventHandler<GetUserCompletedEventArgs>(client_GetUserCompleted);
client.GetUserAsync("webabcd2");
}
void client_GetUserCompleted(object sender, GetUserCompletedEventArgs e)
{
/*
* 方法名CompletedEventArgs.Error - 该异步操作期间是否发生了错误
* 方法名CompletedEventArgs.Result - 异步操作返回的结果。本例为 User 类型
* 方法名CompletedEventArgs.UserState - 用户标识
*/
if (e.Error != null)
{
lblMsg.Text += e.Error.ToString() + "\r\n";
return;
}
if (e.Cancelled != true)
{
OutputResult(e.Result);
}
}
void Demo3()
{
// UI 线程
_syncContext = SynchronizationContext.Current;
/*
* ChannelFactory<T>.CreateChannel() - 创建 T 类型的信道
* 服务名.Begin方法名() - 后台线程上异步调用指定方法(最后一个参数为 代理对象)
*/
WCFService client = new ChannelFactory<WCFService>(new BasicHttpBinding(), new EndpointAddress("http://localhost:3036/WCFService.svc")).CreateChannel();
client.BeginGetUser("webabcd3", new AsyncCallback(ResponseCallback), client);
}
private void ResponseCallback(IAsyncResult result)
{
WCFService client = result.AsyncState as WCFService;
// 服务名.End方法名() - 获取在后台线程(非UI线程)上异步调用的结果
User user = client.EndGetUser(result);
// 调用 UI 线程
_syncContext.Post(GetResponse, user);
}
private void GetResponse(object state)
{
OutputResult(state as User);
}
/// <summary>
/// 输出异步调用 WCF 服务的方法后返回的结果
/// </summary>
/// <param name="user"></param>
void OutputResult(User user)
{
lblMsg.Text += string.Format("姓名:{0};生日:{1}\r\n",
user.Name,
user.DayOfBirth.ToString("yyyy-MM-dd"));
}
}
}
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Silverlight20.WCFServiceReference;
using System.Threading;
using System.ServiceModel;
namespace Silverlight20.Communication
{
public partial class WCF : UserControl
{
SynchronizationContext _syncContext;
/// <summary>
/// 演示 Silverlight 调用 WCF 服务
/// </summary>
public WCF()
{
InitializeComponent();
// 代理的配置信息在配置文件中,UI线程上的异步调用
Demo();
// 代理的配置信息在程序中指定,UI线程上的异步调用
Demo2();
// 后台线程(非UI线程)上的异步调用)
Demo3();
}
void Demo()
{
/*
* 服务名Client - 系统自动生成的代理类
* 方法名Completed - 调用指定的方法完成后所触发的事件
* 方法名Async(参数1, 参数2 , object 用户标识) - 异步调用指定的方法
* Abort() - 取消调用
*/
WCFServiceClient client = new WCFServiceClient();
client.GetUserCompleted += new EventHandler<GetUserCompletedEventArgs>(client_GetUserCompleted);
client.GetUserAsync("webabcd");
}
void Demo2()
{
/*
* 服务名Client - 其构造函数可以动态地指定代理的配置信息(Silverlight 2.0 调用 WCF 只支持 BasicHttpBinding)
*/
WCFServiceClient client = new WCFServiceClient(new BasicHttpBinding(), new EndpointAddress("http://localhost:3036/WCFService.svc"));
client.GetUserCompleted += new EventHandler<GetUserCompletedEventArgs>(client_GetUserCompleted);
client.GetUserAsync("webabcd2");
}
void client_GetUserCompleted(object sender, GetUserCompletedEventArgs e)
{
/*
* 方法名CompletedEventArgs.Error - 该异步操作期间是否发生了错误
* 方法名CompletedEventArgs.Result - 异步操作返回的结果。本例为 User 类型
* 方法名CompletedEventArgs.UserState - 用户标识
*/
if (e.Error != null)
{
lblMsg.Text += e.Error.ToString() + "\r\n";
return;
}
if (e.Cancelled != true)
{
OutputResult(e.Result);
}
}
void Demo3()
{
// UI 线程
_syncContext = SynchronizationContext.Current;
/*
* ChannelFactory<T>.CreateChannel() - 创建 T 类型的信道
* 服务名.Begin方法名() - 后台线程上异步调用指定方法(最后一个参数为 代理对象)
*/
WCFService client = new ChannelFactory<WCFService>(new BasicHttpBinding(), new EndpointAddress("http://localhost:3036/WCFService.svc")).CreateChannel();
client.BeginGetUser("webabcd3", new AsyncCallback(ResponseCallback), client);
}
private void ResponseCallback(IAsyncResult result)
{
WCFService client = result.AsyncState as WCFService;
// 服务名.End方法名() - 获取在后台线程(非UI线程)上异步调用的结果
User user = client.EndGetUser(result);
// 调用 UI 线程
_syncContext.Post(GetResponse, user);
}
private void GetResponse(object state)
{
OutputResult(state as User);
}
/// <summary>
/// 输出异步调用 WCF 服务的方法后返回的结果
/// </summary>
/// <param name="user"></param>
void OutputResult(User user)
{
lblMsg.Text += string.Format("姓名:{0};生日:{1}\r\n",
user.Name,
user.DayOfBirth.ToString("yyyy-MM-dd"));
}
}
}
2、对客户端与服务端传输的消息做加密
WCFService.cs(WCF 服务)
using System;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.Collections.Generic;
using System.Text;
using System.Security.Cryptography;
using System.IO;
/// <summary>
/// 提供 WCF 服务的类
/// </summary>
[ServiceContract]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class WCFService
{
/// <summary>
/// 返回指定的 User 对象(用于演示传输信息的加密/解密)
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
[OperationContract]
public User GetUserByCryptography(string name)
{
return new User { Name = Decrypt(name), DayOfBirth = new DateTime(1980, 2, 14) };
}
/// <summary>
/// 解密数据
/// </summary>
/// <param name="input">加密后的字符串</param>
/// <returns>加密前的字符串</returns>
public string Decrypt(string input)
{
// 盐值(与加密时设置的值一致)
string saltValue = "saltValue";
// 密码值(与加密时设置的值一致)
string pwdValue = "pwdValue";
byte[] encryptBytes = Convert.FromBase64String(input);
byte[] salt = Encoding.UTF8.GetBytes(saltValue);
AesManaged aes = new AesManaged();
Rfc2898DeriveBytes rfc = new Rfc2898DeriveBytes(pwdValue, salt);
aes.BlockSize = aes.LegalBlockSizes[0].MaxSize;
aes.KeySize = aes.LegalKeySizes[0].MaxSize;
aes.Key = rfc.GetBytes(aes.KeySize / 8);
aes.IV = rfc.GetBytes(aes.BlockSize / 8);
// 用当前的 Key 属性和初始化向量 IV 创建对称解密器对象
ICryptoTransform decryptTransform = aes.CreateDecryptor();
// 解密后的输出流
MemoryStream decryptStream = new MemoryStream();
// 将解密后的目标流(decryptStream)与解密转换(decryptTransform)相连接
CryptoStream decryptor = new CryptoStream(decryptStream, decryptTransform, CryptoStreamMode.Write);
// 将一个字节序列写入当前 CryptoStream (完成解密的过程)
decryptor.Write(encryptBytes, 0, encryptBytes.Length);
decryptor.Close();
// 将解密后所得到的流转换为字符串
byte[] decryptBytes = decryptStream.ToArray();
string decryptedString = UTF8Encoding.UTF8.GetString(decryptBytes, 0, decryptBytes.Length);
return decryptedString;
}
}
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.Collections.Generic;
using System.Text;
using System.Security.Cryptography;
using System.IO;
/// <summary>
/// 提供 WCF 服务的类
/// </summary>
[ServiceContract]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class WCFService
{
/// <summary>
/// 返回指定的 User 对象(用于演示传输信息的加密/解密)
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
[OperationContract]
public User GetUserByCryptography(string name)
{
return new User { Name = Decrypt(name), DayOfBirth = new DateTime(1980, 2, 14) };
}
/// <summary>
/// 解密数据
/// </summary>
/// <param name="input">加密后的字符串</param>
/// <returns>加密前的字符串</returns>
public string Decrypt(string input)
{
// 盐值(与加密时设置的值一致)
string saltValue = "saltValue";
// 密码值(与加密时设置的值一致)
string pwdValue = "pwdValue";
byte[] encryptBytes = Convert.FromBase64String(input);
byte[] salt = Encoding.UTF8.GetBytes(saltValue);
AesManaged aes = new AesManaged();
Rfc2898DeriveBytes rfc = new Rfc2898DeriveBytes(pwdValue, salt);
aes.BlockSize = aes.LegalBlockSizes[0].MaxSize;
aes.KeySize = aes.LegalKeySizes[0].MaxSize;
aes.Key = rfc.GetBytes(aes.KeySize / 8);
aes.IV = rfc.GetBytes(aes.BlockSize / 8);
// 用当前的 Key 属性和初始化向量 IV 创建对称解密器对象
ICryptoTransform decryptTransform = aes.CreateDecryptor();
// 解密后的输出流
MemoryStream decryptStream = new MemoryStream();
// 将解密后的目标流(decryptStream)与解密转换(decryptTransform)相连接
CryptoStream decryptor = new CryptoStream(decryptStream, decryptTransform, CryptoStreamMode.Write);
// 将一个字节序列写入当前 CryptoStream (完成解密的过程)
decryptor.Write(encryptBytes, 0, encryptBytes.Length);
decryptor.Close();
// 将解密后所得到的流转换为字符串
byte[] decryptBytes = decryptStream.ToArray();
string decryptedString = UTF8Encoding.UTF8.GetString(decryptBytes, 0, decryptBytes.Length);
return decryptedString;
}
}
Cryptography.xaml
<UserControl x:Class="Silverlight20.Communication.Cryptography"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<StackPanel HorizontalAlignment="Left" Margin="5">
<TextBlock x:Name="lblMsg" />
</StackPanel>
</UserControl>
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<StackPanel HorizontalAlignment="Left" Margin="5">
<TextBlock x:Name="lblMsg" />
</StackPanel>
</UserControl>
Cryptography.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Silverlight20.WCFServiceReference;
using System.Text;
using System.Security.Cryptography;
using System.IO;
namespace Silverlight20.Communication
{
public partial class Cryptography : UserControl
{
public Cryptography()
{
InitializeComponent();
Demo();
}
void Demo()
{
WCFServiceClient client = new WCFServiceClient();
client.GetUserByCryptographyCompleted+=new EventHandler<GetUserByCryptographyCompletedEventArgs>(client_GetUserByCryptographyCompleted);
client.GetUserByCryptographyAsync(Encrypt("webabcd"));
}
void client_GetUserByCryptographyCompleted(object sender, GetUserByCryptographyCompletedEventArgs e)
{
if (e.Error != null)
{
lblMsg.Text += e.Error.ToString() + "\r\n";
return;
}
if (e.Cancelled != true)
{
lblMsg.Text += string.Format("姓名:{0};生日:{1}\r\n",
e.Result.Name,
e.Result.DayOfBirth.ToString("yyyy-MM-dd"));
}
}
/// <summary>
/// 加密数据
/// </summary>
/// <param name="input">加密前的字符串</param>
/// <returns>加密后的字符串</returns>
private string Encrypt(string input)
{
// 盐值
string saltValue = "saltValue";
// 密码值
string pwdValue = "pwdValue";
byte[] data = UTF8Encoding.UTF8.GetBytes(input);
byte[] salt = UTF8Encoding.UTF8.GetBytes(saltValue);
// AesManaged - 高级加密标准(AES) 对称算法的管理类
AesManaged aes = new AesManaged();
// Rfc2898DeriveBytes - 通过使用基于 HMACSHA1 的伪随机数生成器,实现基于密码的密钥派生功能 (PBKDF2 - 一种基于密码的密钥派生函数)
// 通过 密码 和 salt 派生密钥
Rfc2898DeriveBytes rfc = new Rfc2898DeriveBytes(pwdValue, salt);
/*
* AesManaged.BlockSize - 加密操作的块大小(单位:bit)
* AesManaged.LegalBlockSizes - 对称算法支持的块大小(单位:bit)
* AesManaged.KeySize - 对称算法的密钥大小(单位:bit)
* AesManaged.LegalKeySizes - 对称算法支持的密钥大小(单位:bit)
* AesManaged.Key - 对称算法的密钥
* AesManaged.IV - 对称算法的密钥大小
* Rfc2898DeriveBytes.GetBytes(int 需要生成的伪随机密钥字节数) - 生成密钥
*/
aes.BlockSize = aes.LegalBlockSizes[0].MaxSize;
aes.KeySize = aes.LegalKeySizes[0].MaxSize;
aes.Key = rfc.GetBytes(aes.KeySize / 8);
aes.IV = rfc.GetBytes(aes.BlockSize / 8);
// 用当前的 Key 属性和初始化向量 IV 创建对称加密器对象
ICryptoTransform encryptTransform = aes.CreateEncryptor();
// 加密后的输出流
MemoryStream encryptStream = new MemoryStream();
// 将加密后的目标流(encryptStream)与加密转换(encryptTransform)相连接
CryptoStream encryptor = new CryptoStream(encryptStream, encryptTransform, CryptoStreamMode.Write);
// 将一个字节序列写入当前 CryptoStream (完成加密的过程)
encryptor.Write(data, 0, data.Length);
encryptor.Close();
// 将加密后所得到的流转换成字节数组,再用Base64编码将其转换为字符串
string encryptedString = Convert.ToBase64String(encryptStream.ToArray());
return encryptedString;
}
}
}
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Silverlight20.WCFServiceReference;
using System.Text;
using System.Security.Cryptography;
using System.IO;
namespace Silverlight20.Communication
{
public partial class Cryptography : UserControl
{
public Cryptography()
{
InitializeComponent();
Demo();
}
void Demo()
{
WCFServiceClient client = new WCFServiceClient();
client.GetUserByCryptographyCompleted+=new EventHandler<GetUserByCryptographyCompletedEventArgs>(client_GetUserByCryptographyCompleted);
client.GetUserByCryptographyAsync(Encrypt("webabcd"));
}
void client_GetUserByCryptographyCompleted(object sender, GetUserByCryptographyCompletedEventArgs e)
{
if (e.Error != null)
{
lblMsg.Text += e.Error.ToString() + "\r\n";
return;
}
if (e.Cancelled != true)
{
lblMsg.Text += string.Format("姓名:{0};生日:{1}\r\n",
e.Result.Name,
e.Result.DayOfBirth.ToString("yyyy-MM-dd"));
}
}
/// <summary>
/// 加密数据
/// </summary>
/// <param name="input">加密前的字符串</param>
/// <returns>加密后的字符串</returns>
private string Encrypt(string input)
{
// 盐值
string saltValue = "saltValue";
// 密码值
string pwdValue = "pwdValue";
byte[] data = UTF8Encoding.UTF8.GetBytes(input);
byte[] salt = UTF8Encoding.UTF8.GetBytes(saltValue);
// AesManaged - 高级加密标准(AES) 对称算法的管理类
AesManaged aes = new AesManaged();
// Rfc2898DeriveBytes - 通过使用基于 HMACSHA1 的伪随机数生成器,实现基于密码的密钥派生功能 (PBKDF2 - 一种基于密码的密钥派生函数)
// 通过 密码 和 salt 派生密钥
Rfc2898DeriveBytes rfc = new Rfc2898DeriveBytes(pwdValue, salt);
/*
* AesManaged.BlockSize - 加密操作的块大小(单位:bit)
* AesManaged.LegalBlockSizes - 对称算法支持的块大小(单位:bit)
* AesManaged.KeySize - 对称算法的密钥大小(单位:bit)
* AesManaged.LegalKeySizes - 对称算法支持的密钥大小(单位:bit)
* AesManaged.Key - 对称算法的密钥
* AesManaged.IV - 对称算法的密钥大小
* Rfc2898DeriveBytes.GetBytes(int 需要生成的伪随机密钥字节数) - 生成密钥
*/
aes.BlockSize = aes.LegalBlockSizes[0].MaxSize;
aes.KeySize = aes.LegalKeySizes[0].MaxSize;
aes.Key = rfc.GetBytes(aes.KeySize / 8);
aes.IV = rfc.GetBytes(aes.BlockSize / 8);
// 用当前的 Key 属性和初始化向量 IV 创建对称加密器对象
ICryptoTransform encryptTransform = aes.CreateEncryptor();
// 加密后的输出流
MemoryStream encryptStream = new MemoryStream();
// 将加密后的目标流(encryptStream)与加密转换(encryptTransform)相连接
CryptoStream encryptor = new CryptoStream(encryptStream, encryptTransform, CryptoStreamMode.Write);
// 将一个字节序列写入当前 CryptoStream (完成加密的过程)
encryptor.Write(data, 0, data.Length);
encryptor.Close();
// 将加密后所得到的流转换成字节数组,再用Base64编码将其转换为字符串
string encryptedString = Convert.ToBase64String(encryptStream.ToArray());
return encryptedString;
}
}
}
OK
[源码下载]