<a href="http://webabcd.blog.51cto.com/1787395/342790" target="_blank">[索引頁]</a>
<a href="http://down.51cto.com/data/100302" target="_blank">[源碼下載下傳]</a>
穩紮穩打Silverlight(22) - 2.0通信之調用WCF服務, 對傳輸資訊做加密
介紹
Silverlight 2.0 調用 WCF 服務,對用戶端與服務端傳輸的消息做加密
在 Visual Studio 2008 中使用"添加服務引用"會自動生成代理類。隻支援BasicHttpBinding
線上DEMO
<a href="http://webabcd.blog.51cto.com/1787395/342779">http://webabcd.blog.51cto.com/1787395/342779</a>
示例
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 的所有通信均為異步
關于政策檔案詳見文檔
-->
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) };
}
}
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>
WCF.xaml.cs
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;
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.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);
/// 輸出異步調用 WCF 服務的方法後傳回的結果
/// <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、對用戶端與服務端傳輸的消息做加密
/// 傳回指定的 User 對象(用于示範傳輸資訊的加密/解密)
/// <param name="name"></param>
public User GetUserByCryptography(string name)
return new User { Name = Decrypt(name), DayOfBirth = new DateTime(1980, 2, 14) };
/// 解密資料
/// <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"
Cryptography.xaml.cs
public partial class Cryptography : UserControl
public Cryptography()
client.GetUserByCryptographyCompleted+=new EventHandler<GetUserByCryptographyCompletedEventArgs>(client_GetUserByCryptographyCompleted);
client.GetUserByCryptographyAsync(Encrypt("webabcd"));
void client_GetUserByCryptographyCompleted(object sender, GetUserByCryptographyCompletedEventArgs e)
lblMsg.Text += string.Format("姓名:{0};生日:{1}\r\n",
e.Result.Name,
e.Result.DayOfBirth.ToString("yyyy-MM-dd"));
/// 加密資料
/// <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
本文轉自webabcd 51CTO部落格,原文連結:http://blog.51cto.com/webabcd/343130,如需轉載請自行聯系原作者