Page 1
Page 2
Page 3
Page 4
Tracing
When testing the above, I had to do
alot more debugging then I preferred. This involved a lot
of sniffing what was actually being sent over the wire.
My preferred method is to use the Soap Toolkit Trace Utility.
You can redirect to it at a certain port, and it will listen
for incoming requests and then redirect to another endpoint.
The really nice thing is that it can parse DIME messages
as well. Occasionally my app would exception because of
'no end of entity mark', this seems to be caused by a parsing
bug in the Soap Toolkit Trace Utility? If I would make the
same WS call again immediately after, it would work fine.
Also, I used the de facto TraceExtension SoapExtension example.
Only changes it needed were to remove the SoapServerMessage
usage and to write out to a filepath that exists on the
SP. Then the problem is being able to view the actually
file because there is no file explorer on SP. One of the
managed code samples that comes with the SP SDK is a file
explorer (CompactNav). With a little code addition (below),
it can open .txt and .xml files in Pocket IE. Another option
might be to use the ActiveSync-Emulator powertoy that has
come out, which might let you browse to the file, although
it has been way too finicky for me to use. Finally, WSE
has some nice tracing options built-in for the server-side
if you control that endpoint as well.
else if (fullPath[depth].ToLower().EndsWith(".txt") ||
fullPath[depth].ToLower().EndsWith(".xml"))
{
//add to bottom of CompactNav.listView1_ItemActivate
//after if (fullPath[depth].ToLower().EndsWith(".exe"))
ProcessInfo pi = new ProcessInfo();
// launch the exe using our pinvoked CreateProcess call
CreateProcess(@"\Windows\iexplore.exe", fullPath[depth], pi);
// back up since we didn't actually enter the directory
--depth;
}
WS-Routing
This specification is basically dead.
WS 2.0 uses WS-Addressing instead. I did go ahead and update
this SoapHeader to better support the spec for existing
WSE 1.0 apps that are already live. Tested it against the
WSE1 Routing sample, which ends up routing the call
to the SumService web service. NOTE the referralCache.config
change below
//request
<wsrp:path soap:actor="http://schemas.xmlsoap.org/soap/actor/next" soap:mustUnderstand="1"
xmlns:wsrp="http://schemas.xmlsoap.org/rp">
<wsrp:action>http://microsoft.com/wse/samples/SumService/AddInt</wsrp:action>
<wsrp:to>http://localhost/wsequickstart/router/sumservice.asmx</wsrp:to>
<wsrp:id>uuid:a435db9a-f8a1-453a-a75e-8ca8839b3863</wsrp:id>
</wsrp:path>
WS-Referral
This spec. all happens on the server,
to handle the actual routing of messages, so we do not have
to worry about it from the client side. It is worth noting
that you will have to change the referral.config file to
develop with a SmartDevice. This is because SmartDevices
cannot call web services with 'localhost' domains, and have
to use machine name or ip address. The WSE Routing samples
use localhost, so have to be modified to the ip address
or machine name that you use from your device. If you
have already called the WSE Routing sample, then referralCache.config
will be locked, so you will have to iisreset to unlock it
and make the changes. NOTE that capitalization might be
an issue. Also if you are using a Soap tracing mechanism
that depends on port redirection, then you will have to
make changes for that as well.
WS-Addressing
I dont really like this spec. because
it has a number of SoapHeaders that are scattered about and
not contained by something like an <Addressing/> parent
element. I did implement it as SoapHeaders, as well as in
a SoapExtension (below). Tested it against the WSE2 Routing
sample, which calls the BaseStockService web service. NOTE
the referralCache.config change above
//request
<wsa:Action>http://stockservice.contoso.com/wse/samples/2003/06/StockQuoteRequest</wsa:Action>
<wsa:From>
<wsa:Address>http://schemas.xmlsoap.org/ws/2003/03/addressing/role/anonymous</wsa:Address>
</wsa:From>
<wsa:MessageID>uuid:140eaeb5-bb6d-58b1-8f31-ed56619e353b</wsa:MessageID>
<wsa:To>http://notebook:8080/TimeStampService/TimeStamp.asmx</wsa:To>
//response
<wsa:From>
<wsa:Address>http://schemas.xmlsoap.org/ws/2003/03/addressing/role/anonymous</wsa:Address>
</wsa:From>
<wsa:MessageID>uuid:de8f245e-cb33-4366-bfb5-70f9445f6b17</wsa:MessageID>
SoapExtension
Manually adding all those SoapHeaders
for Timestamp and Addressing got annoying. With the
WSE, routing and timestamp info is sent from the client
without you having to specify anything. I wanted this same
sort of automagic behavior, so decided to wrap the SoapHeaders
with a SoapExtension. In the SoapExtension, on BeforeSerialize,
you can add SoapHeaders to a Headers collection. On .NETfx,
these will get serialized and sent out just fine, but not
on .NETcf. On .NETcf, you have to hook AfterSerialize, load
the stream into an XmlDocument, add the proper XmlElements
to the doc, and then handle the stream properly. This sucks,
because you lose all the typing. Also, when calling XmlDocument.Load,
.NETcf closes the underlying stream, while .NETfx does not.
A related trick (per Alex Feinman) to this is to add a generic
SoapFault to the web ref proxy, and then you can add a typed
SoapHeader and it will be sent appropriately.
The other problem with SoapExtensions
is that you have to register them using Attributes on .NETcf.
I wish there was a programmatic way, so that my application
logic could add them dynamically. Christian Weyer came up
with a slick way to register them on .NETfx by reflecting
to the app.config way of registering files; there should
be a similar way to do the same through the client-side
attribute method although i have not dug into it.
Finally, there is another problem when
stacking SoapExtensions. On the full framework, you can
stack multiple SoapExtensionAttributes on top of the client
proxy web method, and each SoapExtension will run in order
based on whether the response is incoming or outgoing. This
fails on the .NETcf because the stream will not get passed
properly from SoapExtension to SoapExtension. You can get
around this by just having one SoapExtension, and call a
handler for each type of logic in the proper order. I really
hope the problems with SoapExtensions get fixed for Whidbey.
Mainly so that most of the code can be moved from doing
Xml manipulation in AfterSerialize and BeforeDeserialize
to working with typed objects in BeforeSerialize and AfterDeserialize.
I would have preferred that programming model instead :(
Proxy Authentication
When calling an external WS, I tried
it behind a proxy that required authentication. Initially,
this was a problem to get the WSDL. The VS.NET 'add web
reference' was not able to handle it, although it looks
like wsdl.exe can. To get around this I used IE to browse
to the WSDL, then saved it locally and reference the locally
saved file in VS.NET to generate the proxy. Once the proxy
was created, then it became a problem when calling the actual
WS. On the .NETcf this was handled by catching a WebException,
and then inserting the proper credentials. On .NETfx
I would have done this by adding NetworkCredentials
to the GlobalProxySelection.Select. Although that class
exists on .NETcf it did not work for me and I had to add
the NetworkCredentials to the webRefProxy.Proxy property
instead. A UI would have to be supplied to let a user
enter credentials, so hopefully this will not happen to
SPs that are wirelessly connected because user input is
a pain
DIME / WS-Attachments
My 1st version of this only was
able to send one attachment out. In DIME this is actually
2 DimeRecords, the 1st being the SoapMessage, and the 2nd
being the actual Attachment. It was also ugly in that you
had to use the HttpWebRequest class directly and build up
the SoapRequest manually. First, I extended this by making
it support multiple attachments going out. Next, I updated
it to support receiving multiple files in a Dime Response.
Finally, I rehooked the SoapExtensions to work with the
modified WSE interface and port to run on .NETcf. This makes
it work with the web reference proxies so you dont have
to manually get the SoapRequest. I doubt that chunking would
work; which is used to break up a file among multiple DimeRecords
in a single DimeMessage. Tested this against the WSE2 Attachments
sample and it should also work for WSE1 DIME-enabled web
services. The .xml files below show the DIME header parsed
by the Soap Toolkit Trace Utility. The .txt files show the
raw HTTP streams. I modified the sample to return DIME as
well, so neither request nor response is your typical SOAP
message
dimeReq.xml
/
dimeReq.txt / dimeRes.xml
/ dimeRes.txt
Cryptograpic Algorithms
I actually wrote the previous parts
of this article (Addressing and DIME) about a month
ago. Then I started tackling WS-Security, and had to do
a major segue. Reason being is that 2 big aspects of WS-Security
are Xml-Encryption and Xml-Signature, both of which depend
heavily on cryptographic algorithms. Since the .NETcf does
not have the System.Security.Cryptography namespace at all,
I spent almost a month filling in those missing pieces.
The result is my
/spCrypt article.
The System.Security.Cryptography wrapping
ended up being rather successful. Both the Xml-Enc and Xml-Sig
specifications name a number of algorithms, and whether
they are required / recommended or optional. For Required,
we are missing AES Block Encryption. In a recent MSDN magazine,
a C# AES implementation was provided that will compile in
.NETcf. It works, except I could not get it to work with
data larger than 16 bytes. Don't know if I was calling it
wrong? Regardless, TripleDes is the other required Symmetric
algorithm, and WSE uses it by default. For key transport
we are missing RSA-OAEP, although we have RSA-PKCS1 which
is used by default. For Recommended algs, we are only missing
a SHA256 hash, but we do have the required SHA1 hash. For
Optional algs, the smartPhone does have Diffie-Hellman for
key agreement, although the full .NETfx does not support
it. Finally, MacTripleDes is not working for the device
but it is not needed for either Xml-Enc or Xml-Sig. Also,
we dont have Rijndael symmetric (related to AES), but its
not needed for WS-Security either. The result is the CryptoApi
wrapping gave us access to just about everything we will
need to continue.
Previous Page
Next Page