Tasks |
Detailed steps |
1. Create a solution |
- Create a blank solution, named SampleSoapExtension
|
2. Create a simple Web Service |
- Add a new C# ASP.NET Web Service Project, called WSForSampleSoapExtension
- Rename Service1.asmx Echo.asmx
- Rename the class name and the constructor name in this service Echo
- Add the following function to the class:
[WebMethod]public string YouSaid(string whatyousaid)
{
return “You said “ + whatyousaid;
}
|
3. Create a test program for the Web Service |
- Add a new C# Console App, called Test
- Rename Class1.cs Test.cs
- Add a Web Reference to the WSForSampleSoapExtension serviced. Add the following code to the Main function
localhost.Echo e = new localhost.Echo();
Console.WriteLine(e.YouSaid(“Howdy!”));
- Set Test to be the Startup Project
- Set a breakpoint on the curly brace after at the end of Main
- Build and debug; when you reach the breakpoint, the console window should show the message You said Howdy!
|
4. Create an empty SoapExtension |
- Add a new C# Class Library called SampleSoapExtension
- Rename Class1.cs SampleSoapExtension.cs
- Rename the class and delete the constructor
- Add a reference to System.Web.Services.dll
- At the top of the source file, add
using System.Web.Services;
using System.Web.Services.Protocols;
- Add the base class SoapExtension to the class SampleSoapExtensionClass
- In the Class View window, open the SampleSoapExtensionClass all the way to Bases and Interfaces.
- Using Add…Override in the context menu, add class skeletons for ChainStream, both GetInitializer methods, Initialize, and ProcessMessages.
- Modify ChainStream to return stream instead of null.
- Build the solution. You should see the message: 3 succeeded
|
5. Create an attribute to apply the extension to the Web Service |
- Add a new public class called SampleSoapExtensionAttribute that extends SoapExtensionAttribute
- Using the Class View window, add overrides for ExtensionType and Priority
- Modify the get part of ExtensionType to return typeof(SampleSoapExtensionClass)
- Add a private member variable of type int called priority
- Modify the Priority property Get part to return priority, and the set part to priority = value
- Decorate the class with the attribute [AttributeUsage(AttributeTargets.Method)]
- Build the solution.
|
6. Apply the SoapExtension to the Web Service |
- Add to the Web Service project a reference to the SampleSoapExtension project.
- Add the line using SampleSoapExtension; to Echo.cs.asmx
- Add the decoration [SampleSoapExtension] to the method YouSaid.
- Build the solution.
- With the breakpoint still on the curly brace at the end of the Main method, debug the solution. It should work exactly as it did before.
|
7. Add logging to the SoapExtension |
- Add the logMessage method to the SampleSoapExtension class.
private void logMessage(string header,string message)
{
FileStream fs = new FileStream("c:\\logs\\log.txt", FileMode.Append,FileAccess.Write);
StreamWriter w = new StreamWriter(fs);
w.WriteLine("--- " + header);
w.WriteLine(message);
w.Flush();
w.Close();
}
- Add using System.IO; to the SampleSoapExtension source file.
- Add an invocation of logMessage(“Initialize”,””);
- Make sure that the logs directory exists and that Everyone has write access to it.
- Build and run the solution. You should have a log file with a single entry. This proves that the soap extension is being invoked.
|
8. Apply the SoapExtension to the client (Test) program |
- Create a new text file, using File/New…/File…
- Add the following lines to this file
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.web>
<webServices>
<soapExtensionTypes>
<add type="SampleSoapExtension.SampleSoapExtensionClass, sampleSoapExtension" priority="0" group="1"/>
</soapExtensionTypes>
</webServices>
</system.web>
</configuration>
- Save the file in the bin/Debug subdirectory of the Test subdirectory of the solution directory.
- Add to the Test project a reference to the SampleSoapExtension project.
- Delete the log.txt file from the logs directory.
- Build and run the solution. This time there will be two entries in the log.txt file—one from the client and one from the server
|
9. Make the SoapExtension actually do something |
- Add two private member variables to the SampleSoapExtensionClass:
private Stream inwardStream;
private Stream outwardStream;
- Replace the method body of ChainStream with:
outwardStream = stream;
inwardStream = new MemoryStream();
return inwardStream;
- Add the following method body to ProcessMessages:
StreamReader r;
StreamWriter w;
switch (message.Stage)
{
case SoapMessageStage.BeforeDeserialize:
logMessage("BeforeDeserialize",message.GetType().ToString());
r = new StreamReader(outwardStream);
w = new StreamWriter(inwardStream);
w.Write(r.ReadToEnd());
w.Flush();
inwardStream.Position = 0;
break;
case SoapMessageStage.AfterSerialize:
logMessage("AfterSerialize",message.GetType().ToString());
inwardStream.Position = 0;
r = new StreamReader(inwardStream);
w = new StreamWriter(outwardStream);
w.Write(r.ReadToEnd()); w.Flush();
break;
}
- Delete the log file, then build and run the program. You will see the following progression of calls:
Initialize
AfterSerialize with a type of ClientSoapMessage
Initialize
BeforeDeserialize with a type of ServerSoapMessage
AfterSerialize with a type of ServerSoapMessage
BeforeDeserialize with a type of ClientSoapMessage |
10. Add the SOAP messages to the log file |
- In the ProcessMessages method of the SampleSoapExtensionClass, add two member variables:
string whatami;
string soapText;
- In the same method, delete the calls to logMessages
- Add the following line at the start of the BeforeDeserialize case:
whatami = (message is SoapClientMessage) ? "Response to Client" : "Request to Server";
- Add the following line at the start of the AfterSerialize case:
whatami = (message is SoapClientMessage) ? "Request from Client" : "Response from Server";
- Replace the line
w.write(r.ReadToEnd()); in both cases with:
soapText = r.ReadToEnd();
logMessage(whatami,soapText);
w.Write(soapText);
- Delete the log file, then build and run the program. You will see the same progression of calls as in 9 above, but with clearer descriptions and the actual SOAP messages
|
11. |
- Add the following helper functions to the SampleSoapExtensionClass:
private void bumpup(ref StringBuilder instr)
{
for (int i=0; i<instr.Length; i++)
if (instr[i] >= 'a' && instr[i] < 'z')
instr[i] = Convert.ToChar(Convert.ToByte(instr[i])+1);
else if (instr[i] == 'z')
instr[i] = 'a';
}
private void bumpdown(ref StringBuilder instr)
{
for (int i=0; i<instr.Length; i++)
if (instr[i] > 'a' && instr[i] <= 'z')
instr[i] = Convert.ToChar(Convert.ToByte(instr[i])-1);
else if (instr[i] == 'a')
instr[i] = 'z'; }
- At the top of the file, add
using System.Text;
- Replace the declaration of soapText with
StringBuilder sb;
- Replace the three lines you added in 10e above in both cases with:
sb = new StringBuilder();
sb.Append(r.ReadToEnd());
logMessage("Unmodified "+whatami,sb.ToString());
logMessage("Modified "+whatami,sb.ToString());
w.Write(sb.ToString());
- In the BeforeDeserialize case, add
bumpup(ref sb); between the two logMessage calls. In the AfterSerialize case, add
bumpdown(ref sb);
- Delete the log file, then build and run the program. You will see a pair of messages, one unmodified, one ummodified in place of the SOAP messages in 10 above. This demonstrates that obfuscated messages are being passed between the client and the server.
|