You don't need to specify soapExtensionTypes in your config file as well
as an Attribute class. Your EncryptExtensionAttribute is written so you
can individually select the required methods that will use your
implementation of SoapExtension. Whereas the config file will apply the
extension to all members. The attribute class is then specified in the
Web Service proxy class that WSDL.exe creates for you. By the way,
group="High" is invalid. Not sure what the CLR will translate that to
but this needs to be either 0 or 1. 0 means config attributes are
executed first whereas setting it to 1 will execute Attribute configured
extensions first in order of priority for each group of course.
I think the fact that priority in your Attribute class *might* be the
cause. Try setting it to 1 and try it again.
Also in your Attribute class set your overridden method ExtensionType to
return the full name inc namespace of your SoapExtension: ie:
SoapExtensionLib.EncryptExtension.
Simon.
I've just thought, in a windows app, I would put the following lines
into my config file. What do I do in a mobile app where I dont have a
proper .config file?
<system.web>
<webServices>
<soapExtensionTypes>
<add type="SoapExtensionLib.EncryptExtension, SoapExtensionLib"
priority="1" group="High" />
</soapExtensionTypes>
</webServices>
</system.web>
Cheers
James
Hi Simon,
I tried what you suggested and instead of referencing the
SoapExtension assembly from my project, I just deployed it which
worked. If I re-add the reference though, the problem reoccurrs.
Cheers
James
Hmm seems strange...what happens if you remove the
SoapExtensionAttribute from your Web Service proxy method but still
deploy the SoapExtension assembly?
Probebly not related but I did notice your priority field in your
SoapExtensionAttribute is not initialized.
sure...here is the code for the SoapExtension
using System;
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.IO;
using System.Xml;
using System.Text;
using System.Security.Cryptography;
namespace SoapExtensionLib
{
// Define a SOAP Extension that encrypts the SOAP request and
SOAP
// response for the XML Web service method the SOAP extension is
// applied to.
public class EncryptExtension : SoapExtension
{
Stream oldStream;
Stream newStream;
// Save the Stream representing the SOAP request or SOAP
response into
// a local memory buffer.
public override Stream ChainStream(Stream stream)
{
oldStream = stream;
newStream = new MemoryStream();
return newStream;
}
// When the SOAP extension is accessed for the first time,
the XML Web
// service method it is applied to is accessed to store the
file
// name passed in, using the corresponding
SoapExtensionAttribute.
public override object GetInitializer(LogicalMethodInfo
methodInfo, SoapExtensionAttribute attribute)
{
return null;
}
// The SOAP extension was configured to run using a
configuration file
// instead of an attribute applied to a specific XML Web
service
// method.
public override object GetInitializer(Type WebServiceType)
{
return null;
}
// Receive the file name stored by GetInitializer and store
it in a
// member variable for this specific instance.
public override void Initialize(object initializer)
{
return;
}
// If the SoapMessageStage is such that the SoapRequest or
// SoapResponse is still in the SOAP format to be sent or
received,
// save it out to a file.
public override void ProcessMessage(SoapMessage message)
{
switch (message.Stage)
{
case SoapMessageStage.BeforeSerialize:
break;
case SoapMessageStage.AfterSerialize:
Encrypt();
break;
case SoapMessageStage.BeforeDeserialize:
Decrypt();
break;
case SoapMessageStage.AfterDeserialize:
break;
default:
throw new Exception("invalid stage");
}
}
public void Encrypt()
{
newStream.Position = 0;
newStream = EncryptHeader(newStream);
Copy(newStream, oldStream);
}
public void Decrypt()
{
Stream unEncryptedStream = DecryptHeader(oldStream);
Copy(unEncryptedStream, newStream);
newStream.Position = 0;
}
public Stream EncryptHeader(Stream streamToEncrypt)
{
streamToEncrypt.Position = 0;
XmlTextReader reader = new
XmlTextReader(streamToEncrypt);
XmlDocument dom = new XmlDocument();
dom.Load(reader);
XmlNamespaceManager nsmgr = new
XmlNamespaceManager(dom.NameTable);
nsmgr.AddNamespace("soap",
"
http://schemas.xmlsoap.org/soap/envelope/");
XmlNode node = dom.SelectSingleNode("//soap:Header",
nsmgr);
if (node != null)
{
node = node.FirstChild.FirstChild;
node.InnerText = Encrypt(node.InnerText);
}
MemoryStream ms = new MemoryStream();
dom.Save(ms);
ms.Position = 0;
return ms;
}
private MemoryStream DecryptHeader(Stream streamToDecrypt)
{
if (streamToDecrypt.CanSeek)
{
streamToDecrypt.Position = 0;
}
XmlTextReader reader = new
XmlTextReader(streamToDecrypt);
XmlDocument dom = new XmlDocument();
dom.Load(reader);
XmlNamespaceManager nsmgr = new
XmlNamespaceManager(dom.NameTable);
nsmgr.AddNamespace("soap",
"
http://schemas.xmlsoap.org/soap/envelope/");
XmlNode node = dom.SelectSingleNode("//soap:Header",
nsmgr);
if (node != null)
{
node = node.FirstChild.FirstChild;
node.InnerText = Decrypt(node.InnerText);
}
MemoryStream ms = new MemoryStream();
dom.Save(ms);
ms.Position = 0;
return ms;
}
private Byte[] key = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab,
0xcd, 0xef };
private Byte[] IV = { 0x12, 0x34, 0x56, 0x78, 0x90, 0xab,
0xcd, 0xef };
public string Encrypt(string stringToEncrypt)
{
DESCryptoServiceProvider des = new
DESCryptoServiceProvider();
byte[] inputByteArray =
Encoding.Unicode.GetBytes(stringToEncrypt);
MemoryStream ms = new MemoryStream();
CryptoStream cs = new CryptoStream(ms,
des.CreateEncryptor(key, IV), CryptoStreamMode.Write);
cs.Write(inputByteArray, 0, inputByteArray.Length);
cs.FlushFinalBlock();
return Convert.ToBase64String(ms.ToArray());
}
public string Decrypt(string stringToDecrypt)
{
DESCryptoServiceProvider des = new
DESCryptoServiceProvider();
byte[] inputByteArray =
Convert.FromBase64String(stringToDecrypt);
MemoryStream ms = new MemoryStream();
CryptoStream cs = new CryptoStream(ms,
des.CreateDecryptor(key, IV), CryptoStreamMode.Write);
cs.Write(inputByteArray, 0, inputByteArray.Length);
cs.FlushFinalBlock();
return Encoding.Unicode.GetString(ms.ToArray());
}
void Copy(Stream from, Stream to)
{
TextReader reader = new StreamReader(from);
TextWriter writer = new StreamWriter(to);
writer.WriteLine(reader.ReadToEnd());
writer.Flush();
}
}
// Create a SoapExtensionAttribute for the SOAP Extension that
can be
// applied to an XML Web service method.
[AttributeUsage(AttributeTargets.Method)]
public class EncryptExtensionAttribute : SoapExtensionAttribute
{
private int priority;
public override Type ExtensionType
{
get { return typeof(EncryptExtension); }
}
public override int Priority
{
get { return priority; }
set { priority = value; }
}
}
}
Can you show us your SoapExtension code?
Simon.
A colleague of mine has written a web service and a SoapExtension
that I must reference from my windows mobile 5.0 app (developed in
VS2005).
My app was working fine when it referenced just the web service,
deployed ok to a real windows mobile 5.0 device and also to the
emulators from Visual Studio 2005. As soon as the SoapExtension
was added (it is a separate assembly), the project suddenly tries
to include all sorts of assemblies that are not dependencies of
the Mobile App, the SoapExtension or the Web Service (when I look
in my MobileApp\bin\Debug folder there are Dll's like
System.Data.OracleClient.dll that should not be there). Then, when
I try and deploy the app to an emulator or a real device, the
device does not have sufficient memory for all the Dll's.
It this a problem with the compact framework, because we created a
test windows forms app, referenced the web service and the
SoapExtension and this problem does not occur.
Any idea's on how to get around this?
Cheers
James