年过半百的老李头

知足、感恩、平常心

导航

Web服务软件工厂(WSSF)演练之三:创建服务契约和实现方法

Web Services Software Factory

Web服务软件工厂(WSSF)演练之三:创建服务契约和实现方法

关键字:Web Services Software Factory, Service Contracts, Service Implementation

您应该已经完成了本演练的第1部分第2部分,然后再开始这一部分的演练。

今天的教程将为我们的WCF服务创建服务契约和实际实现方法。 首先,在您的解决方案资源管理器中,右键点击MyCryptographyService.model后Add–>New Model。

clip_image001

具体的命名请参见下图所示。

clip_image002

如果您的开发环境没有出现属性窗口,右击空白设计区域,然后单击属性。跟我们创建数据契约一样, Project Mapping Table选择我们对应的项目 “Implementation Technology”下拉列表中选择 WCF Extension。设置“Serializer Type”为DataContractSerializer 。

clip_image003

通过第二部分的练习,你应该熟悉如何操作我们的设计区域 ,工具箱的内容将显示与创建服务契约相关的工具。

clip_image004

拖动一个Service并命名为CryptService,一个Service Contract并命名为CryptService,一个Operation并命名为EncryptString,和两个messages分别命名为 EncryptStringRequest和EncryptStringResponse。到我们的空白设计区域,如图所示排列他们。

clip_image005

使用“Connector”连接工具连接Service Contract Service对象(也可以在Service的属性窗口中设置Service Contract的属性)。下面将是设定Operation和Service Contract及messages之间关系的操作,但这部分使用。“Connector”连接工具有些繁琐,可以直接定义Operation的Service Contract的属性为CryptService,“Request”属性为EncryptStringRequest,“Response”的属性为EncryptStringResponse即可。设置好以后应该如下图所示。

clip_image006

按照上述步骤,从工具箱中在拖动2个Operations到您的设计区域,并分别命名为DecryptString和HashString 。工具箱中在拖动4个Messages到设计区域,并分别命名为DecryptStringRequest 、DecryptStringResponse 、 HashStringRequest 和HashStringResponse 。Operations连接各对象间的连接关系参照EncryptString 的各项属性设置,完成后如下图所示 。

clip_image008

继续努力,我们已经接近成功。下面需要给messages对象添加一些Data Contract Message Part。右键单击EncryptStringRequest选择Add–>Data Contract Message Part。将其命名为EncryptionObject 。单击我们刚刚建立的EncryptionObject,在属性窗口中设置Type。单击(...)按钮,将弹出如下图所示的此对话框。选择逐层展开后选择EncryptionObject单击确定。

clip_image009

clip_image010

继续为DecryptStringRequest对象添加一个Data Contract Message Part 命名为EncryptionObject,为HashStringRequest添加命名为HashObject。并对应设置好Type属性。继续分别为3个Response messages对象添加一个Primitive Message Parts,分别命名为“ReturnValue”。需要注意的是,每个名称输入时要精确,名称字符串结尾不能留有空格,在您采用Copy / Paste名称时尤其要注意这一点,否则检查起来很麻烦。

clip_image011

现在,在设计区域的某个白色地方点击右键,选择Validate All(全部验证)如果返回一些错误,请逐一认真检查。如果全部验证已经通过,右键单击,并选择Generate Code(生成代码)。随后,将会有更多的生成代码出现在MyCryptographyService.ServiceImplementation和MyCryptographyService.ServiceContracts 解决方案的类库项目中。

下一步,右键点击MyCryptographyService.BusinessLogic项目,并选择添加一个Class(类)。命名为CryptographyServiceBusinessLogic.cs 。为了节省时间,我已经准备好了如下的代码,请直接使用如下的代码。

using MyCryptographyService.BusinessEntities;

using MyCryptographyService.DataAccess;

namespace MyCryptographyService.BusinessLogic

{

public class CryptographyServiceBusinessLogic

{

private CryptManager manager = new CryptManager();

public string EncryptString(EncryptionObject encryptionObject)

{

return manager.EncryptString(encryptionObject);

}

public string DecryptString(EncryptionObject encryptionObject)

{

return manager.DecryptString(encryptionObject);

}

public string HashString(HashObject hashObject)

{

return manager.HashString(hashObject);

}

}

}

using MyCryptographyService.BusinessEntities;

using MyCryptographyService.DataAccess;

namespace MyCryptographyService.BusinessLogic

{

///

/// This class isn't going to do much in this tutorial.

/// However, in here, you could apply business logic to your service,

/// and maybe make some decisions about which methods in the Data Access Layer's

/// "manager" that you wanted to call. For this example, it is just an

/// "enterprisey" pass-through to show the concept.

///

public class CryptographyServiceBusinessLogic

{

private CryptManager manager = new CryptManager();

public string EncryptString(EncryptionObject encryptionObject)

{

return manager.EncryptString(encryptionObject);

}

public string DecryptString(EncryptionObject encryptionObject)

{

return manager.DecryptString(encryptionObject);

}

public string HashString(HashObject hashObject)

{

return manager.HashString(hashObject);

}

}

}

Next, right click on the MyCryptographyService.DataAccess project and add a new class called CryptographyServiceManager. The code for it is below.

下一步,右键点击MyCryptographyService.DataAccess项目,并添加一个新类称为CryptographyServiceManager 。它的代码如下。

using System;

using System.IO;

using System.Security.Cryptography;

using System.Text;

using MyCryptographyService.BusinessEntities;

namespace MyCryptographyService.DataAccess

{

/// <SUMMARY>

///

/// </SUMMARY>

public class CryptManager

{

private const string KEY = "$0ftw@r3";

private const string IV = "@p3t30n&";

private DESCryptoServiceProvider des = new DESCryptoServiceProvider();

public CryptManager()

{

des.Key = ASCIIEncoding.ASCII.GetBytes(KEY);

des.IV = ASCIIEncoding.ASCII.GetBytes(IV);

}

public string HashString(HashObject hashObject)

{

switch (hashObject.HashType)

{

case HashType.MD5:

return getMd5Sum(hashObject.StringToHash);

case HashType.SHA256:

return getSha256Hash(hashObject.StringToHash);

default:

throw new NotImplementedException("That Hashing Algorithm is not supported");

}

}

public string EncryptString(EncryptionObject encryptionObject)

{

string cryptText = string.Empty;

switch (encryptionObject.EncryptionAlgorithm)

{

case EncryptionAlgorithm.DES:

cryptText = encryptDes(encryptionObject.Text);

break;

case EncryptionAlgorithm.Rijndael:

cryptText = encryptRijndael(encryptionObject.Text);

break;

default:

throw new NotImplementedException("You provided an algorithm that is not implemented.");

}

return cryptText;

}

public string DecryptString(EncryptionObject encryptionObject)

{

string plainText = string.Empty;

switch (encryptionObject.EncryptionAlgorithm)

{

case EncryptionAlgorithm.DES:

plainText = decryptDes(encryptionObject.Text);

break;

case EncryptionAlgorithm.Rijndael:

plainText = decryptRijndael(encryptionObject.Text);

break;

default:

throw new NotImplementedException("You provided an algorithm that is not implemented.");

}

return plainText;

}

private string encryptDes(string plainText)

{

MemoryStream memoryStream = new MemoryStream();

CryptoStream cryptoStream = new CryptoStream(memoryStream, des.CreateEncryptor(), CryptoStreamMode.Write);

StreamWriter writer = new StreamWriter(cryptoStream);

writer.Write(plainText);

writer.Flush();

cryptoStream.FlushFinalBlock();

writer.Flush();

return Convert.ToBase64String(memoryStream.GetBuffer(), 0, (int)memoryStream.Length);

}

private string decryptDes(string cryptText)

{

MemoryStream memoryStream = new MemoryStream(Convert.FromBase64String(cryptText));

CryptoStream cryptoStream = new CryptoStream(memoryStream, des.CreateDecryptor(), CryptoStreamMode.Read);

StreamReader reader = new StreamReader(cryptoStream);

return reader.ReadToEnd();

}

private string encryptRijndael(string plainText)

{

RijndaelManaged rijndaelCipher = new RijndaelManaged();

byte[] plainBytes = Encoding.Unicode.GetBytes(plainText);

byte[] salt = Encoding.ASCII.GetBytes(KEY.Length.ToString());

//This class uses an extension of the PBKDF1 algorithm defined in the PKCS#5 v2.0

//standard to derive bytes suitable for use as key material from a password.

//The standard is documented in IETF RRC 2898.

PasswordDeriveBytes secretKey = new PasswordDeriveBytes(KEY, salt);

//Creates a symmetric encryptor object.

ICryptoTransform encryptor = rijndaelCipher.CreateEncryptor(secretKey.GetBytes(32), secretKey.GetBytes(16));

MemoryStream memoryStream = new MemoryStream();

//Defines a stream that links data streams to cryptographic transformations

CryptoStream cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write);

cryptoStream.Write(plainBytes, 0, plainBytes.Length);

//Writes the final state and clears the buffer

cryptoStream.FlushFinalBlock();

byte[] cipherBytes = memoryStream.ToArray();

memoryStream.Close();

cryptoStream.Close();

string encryptedData = Convert.ToBase64String(cipherBytes);

return encryptedData;

}

private string decryptRijndael(string cipherText)

{

RijndaelManaged rijndaelCipher = new RijndaelManaged();

byte[] encryptedData = Convert.FromBase64String(cipherText);

byte[] salt = Encoding.ASCII.GetBytes(KEY.Length.ToString());

//Making of the key for decryption

PasswordDeriveBytes secretKey = new PasswordDeriveBytes(KEY, salt);

//Creates a symmetric Rijndael decryptor object.

ICryptoTransform decryptor = rijndaelCipher.CreateDecryptor(secretKey.GetBytes(32), secretKey.GetBytes(16));

MemoryStream memoryStream = new MemoryStream(encryptedData);

//Defines the cryptographics stream for decryption.THe stream contains decrpted data

CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read);

byte[] plainText = new byte[encryptedData.Length];

int decryptedCount = cryptoStream.Read(plainText, 0, plainText.Length);

memoryStream.Close();

cryptoStream.Close();

//Converting to string

string decryptedData = Encoding.Unicode.GetString(plainText, 0, decryptedCount);

return decryptedData;

}

private string getMd5Sum(string inputText)

{

// First we need to convert the string into bytes, which

// means using a text encoder.

Encoder encoder = System.Text.Encoding.Unicode.GetEncoder();

// Create a buffer large enough to hold the string

byte[] unicodeText = new byte[inputText.Length * 2];

encoder.GetBytes(inputText.ToCharArray(), 0, inputText.Length, unicodeText, 0, true);

// Now that we have a byte array we can ask the CSP to hash it

MD5 md5 = new MD5CryptoServiceProvider();

byte[] result = md5.ComputeHash(unicodeText);

// Build the final string by converting each byte

// into hex and appending it to a StringBuilder

StringBuilder sb = new StringBuilder();

for (int i = 0; i < result.Length; i++)

{

sb.Append(result[i].ToString("X2"));

}

// And return it

return sb.ToString();

}

private string getSha256Hash(string plainText)

{

byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText);

byte[] saltBytes = Encoding.UTF8.GetBytes(IV);

byte[] plainTextWithSaltBytes =

new byte[plainTextBytes.Length + saltBytes.Length];

for (int i = 0; i < plainTextBytes.Length; i++)

plainTextWithSaltBytes[i] = plainTextBytes[i];

for (int i = 0; i < saltBytes.Length; i++)

plainTextWithSaltBytes[plainTextBytes.Length + i] = saltBytes[i];

HashAlgorithm hash = new SHA256Managed();

byte[] hashBytes = hash.ComputeHash(plainTextWithSaltBytes);

byte[] hashWithSaltBytes = new byte[hashBytes.Length +

saltBytes.Length];

for (int i = 0; i < hashBytes.Length; i++)

hashWithSaltBytes[i] = hashBytes[i];

for (int i = 0; i < saltBytes.Length; i++)

hashWithSaltBytes[hashBytes.Length + i] = saltBytes[i];

string hashValue = Convert.ToBase64String(hashWithSaltBytes);

return hashValue;

}

}

}

using System;

using System.IO;

using System.Security.Cryptography;

using System.Text;

using MyCryptographyService.BusinessEntities;

namespace MyCryptographyService.DataAccess

{

///

/// This is the class where all the action happens, and all gathering of external

/// resources (DB, XML files, registry, etc) should be done from here. Ideally, in this

/// scenerio, you would store your keys external to the application and the

/// transformations would be done here with those keys after they were received.

///

/// NOTE: These implementations are derivations (or outright copying) from samples

/// posted on the internet. Included are:

///

/// http://blog.stevex.net/index.php/c-code-snippet-creating-an-md5-hash-string/

/// http://www.codeproject.com/KB/cs/NET_Encrypt_Decrypt.aspx

/// http://www.obviex.com/samples/hash.aspx

///

public class CryptManager

{

// Note: This is not a tutorial on encryption. Key management

// is paramount in good encryption and of course storing your

// key in plain text in the code is not a good idea. This is

// merely sample code and should not be considered good

// cryptography practice.

private const string KEY = "$0ftw@r3";

private const string IV = "@p3t30n&";

private DESCryptoServiceProvider des = new DESCryptoServiceProvider();

public CryptManager()

{

des.Key = ASCIIEncoding.ASCII.GetBytes(KEY);

des.IV = ASCIIEncoding.ASCII.GetBytes(IV);

}

public string HashString(HashObject hashObject)

{

switch (hashObject.HashType)

{

case HashType.MD5:

return getMd5Sum(hashObject.StringToHash);

case HashType.SHA256:

return getSha256Hash(hashObject.StringToHash);

default:

throw new NotImplementedException("That Hashing Algorithm is not supported");

}

}

public string EncryptString(EncryptionObject encryptionObject)

{

string cryptText = string.Empty;

switch (encryptionObject.EncryptionAlgorithm)

{

case EncryptionAlgorithm.DES:

cryptText = encryptDes(encryptionObject.Text);

break;

case EncryptionAlgorithm.Rijndael:

cryptText = encryptRijndael(encryptionObject.Text);

break;

default:

throw new NotImplementedException("You provided an algorithm that is not implemented.");

}

return cryptText;

}

public string DecryptString(EncryptionObject encryptionObject)

{

string plainText = string.Empty;

switch (encryptionObject.EncryptionAlgorithm)

{

case EncryptionAlgorithm.DES:

plainText = decryptDes(encryptionObject.Text);

break;

case EncryptionAlgorithm.Rijndael:

plainText = decryptRijndael(encryptionObject.Text);

break;

default:

throw new NotImplementedException("You provided an algorithm that is not implemented.");

}

return plainText;

}

private string encryptDes(string plainText)

{

MemoryStream memoryStream = new MemoryStream();

CryptoStream cryptoStream = new CryptoStream(memoryStream, des.CreateEncryptor(), CryptoStreamMode.Write);

StreamWriter writer = new StreamWriter(cryptoStream);

writer.Write(plainText);

writer.Flush();

cryptoStream.FlushFinalBlock();

writer.Flush();

return Convert.ToBase64String(memoryStream.GetBuffer(), 0, (int)memoryStream.Length);

}

private string decryptDes(string cryptText)

{

MemoryStream memoryStream = new MemoryStream(Convert.FromBase64String(cryptText));

CryptoStream cryptoStream = new CryptoStream(memoryStream, des.CreateDecryptor(), CryptoStreamMode.Read);

StreamReader reader = new StreamReader(cryptoStream);

return reader.ReadToEnd();

}

private string encryptRijndael(string plainText)

{

RijndaelManaged rijndaelCipher = new RijndaelManaged();

byte[] plainBytes = Encoding.Unicode.GetBytes(plainText);

byte[] salt = Encoding.ASCII.GetBytes(KEY.Length.ToString());

//This class uses an extension of the PBKDF1 algorithm defined in the PKCS#5 v2.0

//standard to derive bytes suitable for use as key material from a password.

//The standard is documented in IETF RRC 2898.

PasswordDeriveBytes secretKey = new PasswordDeriveBytes(KEY, salt);

//Creates a symmetric encryptor object.

ICryptoTransform encryptor = rijndaelCipher.CreateEncryptor(secretKey.GetBytes(32), secretKey.GetBytes(16));

MemoryStream memoryStream = new MemoryStream();

//Defines a stream that links data streams to cryptographic transformations

CryptoStream cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write);

cryptoStream.Write(plainBytes, 0, plainBytes.Length);

//Writes the final state and clears the buffer

cryptoStream.FlushFinalBlock();

byte[] cipherBytes = memoryStream.ToArray();

memoryStream.Close();

cryptoStream.Close();

string encryptedData = Convert.ToBase64String(cipherBytes);

return encryptedData;

}

private string decryptRijndael(string cipherText)

{

RijndaelManaged rijndaelCipher = new RijndaelManaged();

byte[] encryptedData = Convert.FromBase64String(cipherText);

byte[] salt = Encoding.ASCII.GetBytes(KEY.Length.ToString());

//Making of the key for decryption

PasswordDeriveBytes secretKey = new PasswordDeriveBytes(KEY, salt);

//Creates a symmetric Rijndael decryptor object.

ICryptoTransform decryptor = rijndaelCipher.CreateDecryptor(secretKey.GetBytes(32), secretKey.GetBytes(16));

MemoryStream memoryStream = new MemoryStream(encryptedData);

//Defines the cryptographics stream for decryption.THe stream contains decrpted data

CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read);

byte[] plainText = new byte[encryptedData.Length];

int decryptedCount = cryptoStream.Read(plainText, 0, plainText.Length);

memoryStream.Close();

cryptoStream.Close();

//Converting to string

string decryptedData = Encoding.Unicode.GetString(plainText, 0, decryptedCount);

return decryptedData;

}

private string getMd5Sum(string inputText)

{

// First we need to convert the string into bytes, which

// means using a text encoder.

Encoder encoder = System.Text.Encoding.Unicode.GetEncoder();

// Create a buffer large enough to hold the string

byte[] unicodeText = new byte[inputText.Length * 2];

encoder.GetBytes(inputText.ToCharArray(), 0, inputText.Length, unicodeText, 0, true);

// Now that we have a byte array we can ask the CSP to hash it

MD5 md5 = new MD5CryptoServiceProvider();

byte[] result = md5.ComputeHash(unicodeText);

// Build the final string by converting each byte

// into hex and appending it to a StringBuilder

StringBuilder sb = new StringBuilder();

for (int i = 0; i < result.Length; i++)

{

sb.Append(result[i].ToString("X2"));

}

// And return it

return sb.ToString();

}

private string getSha256Hash(string plainText)

{

byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText);

byte[] saltBytes = Encoding.UTF8.GetBytes(IV);

byte[] plainTextWithSaltBytes =

new byte[plainTextBytes.Length + saltBytes.Length];

for (int i = 0; i < plainTextBytes.Length; i++)

plainTextWithSaltBytes[i] = plainTextBytes[i];

for (int i = 0; i < saltBytes.Length; i++)

plainTextWithSaltBytes[plainTextBytes.Length + i] = saltBytes[i];

HashAlgorithm hash = new SHA256Managed();

byte[] hashBytes = hash.ComputeHash(plainTextWithSaltBytes);

byte[] hashWithSaltBytes = new byte[hashBytes.Length +

saltBytes.Length];

for (int i = 0; i < hashBytes.Length; i++)

hashWithSaltBytes[i] = hashBytes[i];

for (int i = 0; i < saltBytes.Length; i++)

hashWithSaltBytes[hashBytes.Length + i] = saltBytes[i];

string hashValue = Convert.ToBase64String(hashWithSaltBytes);

return hashValue;

}

}

}

在最后完成本部分演练之前,我们还需要做一件事,我们需要将实现的方法联系起来,这将是我们的endpoints(节点)。当我们确定了我们的服务契约,我们定义了一些方法。我们必须实现这些方法,用我们的业务层配合他们,并最终实现我们的数据访问层。

然而,我们每次对服务契约的设计所做任何更改,由于生成的代码将因覆盖而改变,因此我们必须创建另一个partial class代码文件。根据我们自己的实现情况,重写其中的方法,根据提交的请求实现并返回结果。现在MyCryptographyService.ServiceImplementation项目下的CryptImplementation.cs 。文件中,你应该有以下的代码。

using MyCryptographyService.BusinessLogic;

using MyCryptographyService.MessageContracts;

namespace MyCryptographyService.ServiceImplementation

{

public partial class CryptService : CryptServiceBase

{

protected CryptographyServiceBusinessLogic businessLogic = new CryptographyServiceBusinessLogic();

public override EncryptStringResponse EncryptString(EncryptStringRequest request)

{

EncryptStringResponse response = new EncryptStringResponse();

response.ReturnValue = businessLogic.EncryptString(

EncryptionObjectTranslator.TranslateEncryptionObjectToEncryptionObject(request.EncryptionObject));

return response;

}

public override DecryptStringResponse DecryptString(DecryptStringRequest request)

{

DecryptStringResponse response = new DecryptStringResponse();

response.ReturnValue = businessLogic.DecryptString(

EncryptionObjectTranslator.TranslateEncryptionObjectToEncryptionObject(request.EncryptionObject));

return response;

}

public override HashStringResponse HashString(HashStringRequest request)

{

HashStringResponse response = new HashStringResponse();

response.ReturnValue = businessLogic.HashString(

HashObjectTranslator.TranslateHashObjectToHashObject(request.HashObject));

return response;

}

}

}

我们使用Translators的方法创建一些代码,他们对业务实体和数据契约进行了映射。代码应该是非常简单,但如果您有任何问题,请在此留下您的意见,我会尽快答复。

在演练的第4部分,我们会创建托管主机,部署和测试WSDL。敬请关注。

Web服务软件工厂(WSSF)演练之四:创建托管主机,部署和测试WSDL

posted on 2009-02-07 18:19  李运琪  阅读(954)  评论(0编辑  收藏  举报