|
At the end of my last article (WSJ, Vol. 1, issue 4), I promised that
in this article I'd show you an even better way to invoke .NET Web
services from Pocket PCs. In addition, before this month's article is
finished, you'll learn how to invoke .NET Web services from
Java-powered devices.
The .NET Compact Framework
In the first half of this article, we'll focus on invoking
NET Web services from Windows CE-powered devices (including Pocket
PCs) via Microsoft's newest .NET technology: the Compact Framework.
What Is It?
The .NET Compact Framework is the portion of Microsoft's new
NET technology initiative specifically targeted for execution on
mobile devices. The best way to get a clear picture of this in your
head is to contrast it to the rest of .NET.
The rest of .NET allows you to create:
- Windows applications: Full-featured GUI applications intended for
use on desktop computers running the Windows OS.
- Web applications: Apps that serve up various kinds of markup (HTML, etc.)
- Web services: Apps that, you probably know, substitute XML
for the various flavors of presentation markup used by Web
applications.
The .NET Compact Framework adds the whole concept of Mobile
Device applications to the mix. A Mobile Device application is like a
Windows application, in that it is a full-featured GUI application.
Unlike Windows applications, however, Mobile Device applications are
intended to be used on devices instead of desktop computers. Unlike
Web applications and Web services, these applications don't require
the presence of an Internet connection in order to be used.
Develop for Devices As You Develop for Windows
The entire goal behind creating a subset of .NET that is
intended for execution on devices rather than desktops is to allow
the .NET developers to create applications for devices just as they
would for desktops. This ability to create device-based applications
directly from Visual Studio .NET gives the developer:
- The eventual ability to use all of the .NET languages (VB, C#, etc.)
- Access to a large subset of the .NET Framework classes
- A drag-and-drop approach to creating application GUI's
- Step-by-step debugging, just like on the desktop!
How Do You Get It?
To create a successful solution using the .NET Compact
Framework, you need two things. The first of these is the software
needed to turn Visual Studio .NET into a development environment
suitable for creating device-based applications. The other is the set
of runtime classes for installation onto your device(s) in order to
allow them to "speak .NET" (as it were).
At the time of writing, both of these things are available
from Microsoft as a product called the Smart Device Extensions for
Visual Studio .NET. This product is currently bundled with the
Release Candidate version of Visual Studio .NET itself.
There are two ways to get the Release Candidate:
- Be a Microsoft Developers Network subscriber
- Order it on DVD from http://msdn.microsoft.com/vstudio/nextgen/getrc.asp
Once you get it, simply run the Windows installer. My best
experiences with this have been on completely clean machines. So, if
you encounter any errors during setup, you might want to consider
trying it on a completely "fresh" computer (if you have access to
one).
What Do You Do With It?
In this section you'll find sample code for retrieving a
stock quote using the .NET Compact Framework. Better yet, of course,
you'll see how to use it to create a Visual Studio .NET project that
you can compile and deploy to your Pocket PC or emulator.
Coding Your Project
In order to code your project, you
must first create the graphical user interface (GUI), then populate it with the
appropriate event-handling code.
Drawing the GUI
The Forms Designer portion of Visual Studio .NET isn't yet usable
with the Smart Device Extensions, as of the Technology Preview
release. In order to create a GUI for your application, then, we're
going to have to exercise a bit of a workaround:
- Launch Microsoft Visual Studio .NET
- Create a new Windows application
project named "GUI Builder"
- Size Form1 to be 240 x 320 (the size of a
Pocket PC screen)
- Drag a textbox, label, and button onto Form1
- Press F7 to enter Code View
- Press Ctrl-A to select all of the code, then
Ctrl-C to copy it to the clipboard
- Close this project
- Create a new Pocket PC Visual Basic
Project called "NETcfQuote"
- Verify that the project opens in Code View
- Press Ctrl-A to select all of the code, then Ctrl-V to
paste the code from step #6 above
- Comment out the line of code that begins
"Me.AutoScaleBaseSize"
At this point, you've transferred the GUI created in the GUI Builder
project into your NETcfQuote project. With any
luck, this workaround will not be needed in later versions of the
Smart Device Extensions.
Walking Through the Code
We're attempting to write a mobile client for a .NET Web service. It
makes sense, then, that one of the first things we should do is add a
reference to our .NET Web service to our project. One of the most
wonderful parts of the Smart Device Extensions for Visual Studio .NET
is how easy it makes to reference Web services for device-based code:
- Right-click "References" in the Solution
Explorer
- Enter the address of the .NET Web service
we created in last month's article (http://
localhost/Chapter10Server/Service1.asmx)
- Once the page has loaded, click "Add
Reference"
You're now ready to access the get Quote method on this Web
service from a remote device just as easily as you would normally
reference methods on a local component! Could it get any easier?
Chalk one up to Microsoft's side in the battle for simplicity.
At this point, you're ready to add the code from Listing 1 to
your application. Simply copy it, exactly as it appears, immediately
below the line that reads:
#End Region
As you might have guessed, this code is intended to run
whenever the single button on the application's GUI is clicked.
First, it declares a reference to the remote Web service. Then it
calls the getQuote method on this reference, passing in the contents
of the textbox as its first parameter, and an empty variable - price
- as its second. If the method returns successfully, the label is
populated with the contents of price, otherwise an error message is
placed in it.
Compiling and Deploying
In order to compile and test your application, first select
"Pocket PC emulator" from the dropdown that says "<select device>."
Then, press F5. If there are errors, Visual Studio .NET will tell you
that there were problems with the build and prompt you to continue or
abort. If compilation succeeds without a hitch, the new Pocket PC
emulator will launch and your application will appear.
At this point, you should enter the symbol of a NASDAQ stock
in which you are interested into the textbox on the application's
GUI. Then, click the button. Shortly, the most recent price of that
stock should appear in the label on the display.
In order to try your application on a real Pocket PC, you need only:
- Place your Pocket PC in its cradle (attached to your computer
via a cable)
- Choose "Pocket PC Device" from the drop-down instead of
"Pocket PC Emulator"
Java 2, Micro Edition (J2ME)
We'll conclude our look at mobile .NET Web services by
demonstrating how they may be invoked in a truly cross-platform
manner by using the Java platform.
What Is It?
Java is Sun Microsystems' platform for creating software
capable of running on a wide variety of hardware and operating system
combinations. Software written completely in Java can often run on
systems as different as UNIX and Windows without even requiring
recompilation.
With the release of Java 2, Sun divided their platform into
three distinct flavors:
- Enterprise Edition (J2EE)
- Standard Edition (J2SE)
- Micro Edition (J2ME)
J2SE might be referred to as "regular Java" - it's intended
for use with standard, desktop computer applications. J2EE, on the
other hand, is intended for the creation of server-based software,
such as Web applications and distributed, component-based
applications.
J2ME differs from both of the above by focusing on Java code
intended for execution directly on mobile devices. In this sense,
it's Java's direct analog for Microsoft's .NET Compact Frameworks.
How Do You Get It?
The great thing about J2ME is that almost all of the software
needed to create applications for it is freely available for download
off the Internet. On the other hand, the software needed in order to
run these applications on the devices must typically be hard-wired
into devices by the manufacturer (as opposed to being installed
after-the-fact by end-users).
Acquiring the Bits
The first thing that you must download is the Java 2 Software
Development Kit (SDK). This is the bit that takes standard text files
full of Java sourcecode and converts them into binary files full of
Java bytecode. You can get it from http://java.sun.com/j2se/1.3/Text.
The second thing that you should try to lay your hands on is
the J2ME Wireless Toolkit. Although not absolutely essential for
creating J2ME applications, it contains all of the extra libraries
that you would need, plus a great assortment of emulators and
development tools. Since it's also free, why not download it? Go to
http://java.sun.com/products/j2mewtoolkit/Text.
Installation
Both of the above products use standard Windows setup engines
to install and configure themselves on your machine. Just make sure
that you install the JDK first, and then the Wireless Toolkit. (This
is so that the Wireless Toolkit can configure itself to know exactly
where your JDK is - thus making automated compilation and testing
that much easier!)
What Do You Do With It?
Well, this is the point that we've been building to ever
since the start of last month's article: actually invoking a .NET Web
service from a mobile device that has nothing whatsoever to do with
Microsoft.
The key to our approach, as you'll see, is a little bit of
open-source code known as kSOAP. In this section, you'll see how to
use kSOAP to build and deploy a J2ME application that can invoke .NET
Web services from virtually any J2ME-powered device.
Discussing the Code
Let's begin by looking at Listing 2. It begins, like most
Java code, with a series of import statements. The first statement
imports the standard Java IO implementation for MIDP. The next few
lines import various packages specific to MIDP Java. The final four
import statements include support for kSOAP into our MIDlet.
kSOAP can be downloaded free from http://ksoap.enhydra.org.
Also included in the package is some basic Javadoc documentation and
sample code. In my book, Mobile .NET, I go into greater detail than
present space allows about the workings of this fine technology.
However, when you've finished entering and running this code listing,
you should have a fairly strong basic grasp of how the technology is
used.
Inside the FergieStock class, we first find several member
variable declarations. The first of these sets the namespace, which
must match the namespace we chose for our .NET Web service. After
this, a number of GUI elements are declared, and added to the screen
by the default constructor, as you can see.
The pauseApp() and destroyApp() methods are present only
because the MIDlet specification requires them. The startApp() method
is also required and, in this case, serves the purpose of displaying
our initial form on the screen.
All of the real magic in our MIDlet happens when users press
the single command button on the GUI to transmit their stock symbol
up to our Web service. kSOAP's SoapObject component is used to serve
as a proxy for the remote .NET Web service. Its ClassMap object is
used to encapsulate the parameter that will be passed across the wire
to the remote service. Both of these objects are passed into kSOAP's
SoapEnv elope component, which will take care of serializing all of
the kSOAP objects into appropriate SOAP XML for transmission to our
NET Web service.
MIDP's built-in HTTP connectivity is used to facilitate
communications with the remote server. First, the XML for our SOAP
request is transmitted, then the response is received back via the
same HttpConnection method.
kSOAP's SoapEnvelope object provides the technologies needed
in order to interpret the XML that's been returned to our client by
the server. Once the price of the stock has been parsed out, it's
placed into the label on our display. On the other hand, if an error
has been raised, the word "Error" is placed inside the label.
Compiling and Testing
In order to try out the code shown above, follow these steps:
- Save the code from Listing 2 as Fergie Stock.java
- Save the code from Listing 3 as Fergie Stock.jad
- Start the kToolBar application from the Windows Start menu
(in the J2ME Wireless Toolkit program group)
- Select "Open Project," then navigate to "FergieStock.jad" and
choose "Open Project" again
- Click Build and verify that there are no errors
- Click Run
At this point, one of the J2ME Wireless Toolkit's emulators
should open, allowing you to test your new J2ME stock quote client.
Once you've entered a symbol and gotten back its price, congratulate
your-self: you've just talked successfully to Microsoft .NET from
Java!
Final Words
There you have it - how to invoke .NET Web services from
virtually any kind of mobile device. If you're still hungry for more
information about .NET technologies targeted at mobile computing, be
sure to check out my MSN community at www.MobileDotNet.com.
Author Bio
Derek Ferguson is chief technology evangelist for Expand Beyond Corp. He
is a world-renowned author, speaker, and developer who has been
recognized throughout the IT industry for his work.
derek@XB.com
Mobile .Net Web Services Part II, by Derek Ferguson
WSJ Vol 02 Issue 02 - pg.27
Listing 1
Public Class Form1
Inherits System.Windows.Forms.Form
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As _
System.EventArgs) Handles Button1.Click
Dim price As String
Dim ws As localhost.Service1 = New localhost.Service1()
Label1.Text = ""
If ws.getQuote(TextBox1.Text, price) Then
Label1.Text = price
Else
Label1.Text = "No such stock!"
End If
End Sub
End Class
Listing 2
import java.io.*;
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import javax.microedition.io.*;
import org.ksoap.*;
import org.kxml.*;
import org.kxml.io.*;
import org.kxml.parser.*;
public class FergieStock extends MIDlet implements CommandListener {
static final String serviceNamespace = "http://pocketdba.com/webservices/";
Form mainForm = new Form ("Fergie Stock");
TextField fromField = new TextField ("Symbol :", "ALGX", 4, TextField.ANY);
StringItem resultItem = new StringItem ("", "");
Command getCommand = new Command ("Get", Command.SCREEN, 1);
public FergieStock () {
mainForm.append (fromField);
mainForm.append (resultItem);
mainForm.addCommand (getCommand);
mainForm.setCommandListener (this);
}
public void startApp () {
Display.getDisplay (this).setCurrent (mainForm);
}
public void pauseApp () {
}
public void destroyApp (boolean unconditional) {
}
public void commandAction (Command c, Displayable d) {
try {
String from = fromField.getString ();
ByteArrayOutputStream bos = new ByteArrayOutputStream ();
SoapObject request = new SoapObject
(serviceNamespace, "getQuote");
request.addProperty ("symbol", fromField.getString ());
ClassMap classMap = new ClassMap();
classMap.prefixMap = new PrefixMap
(classMap.prefixMap, "tns",
"http://pocketdba.com/webservices/");
SoapEnvelope envelope = new SoapEnvelope (classMap);
envelope.setBody (request);
XmlWriter xw = new XmlWriter (new OutputStreamWriter (bos));
envelope.write (xw);
xw.flush ();
byte [] data = bos.toByteArray();
System.out.println (new String (data));
HttpConnection connection = (HttpConnection) Connector.open
("http://localhost/Chapter10Server/Service1.asmx",Connector.READ_WRITE);
connection.setRequestMethod (HttpConnection.POST);
connection.setRequestProperty ("Content-Type", "text/xml");
connection.setRequestProperty ("Connection", "close");
connection.setRequestProperty
("Content-Length", ""+data.length);
connection.setRequestProperty("SOAPAction",
"\"http://pocketdba.com/webservices/getQuote\"");
OutputStream os = connection.openOutputStream ();
os.write (data);
os.flush ();
InputStream is=((StreamConnection) connection).openInputStream ();
int buffSize=200;
byte[] buff = new byte[buffSize];
ByteArrayOutputStream bytebuff=new ByteArrayOutputStream(buffSize);
int eof=0;
while(eof!=-1) {
eof=is.read(buff);
if (eof!=-1) {
bytebuff.write(buff,0,eof);
}
}
is.close();
String response = new String(bytebuff.toByteArray());
System.out.println (response);
Reader reader = new InputStreamReader(new
ByteArrayInputStream(bytebuff.toByteArray()));
XmlParser parser = new XmlParser (reader);
SoapEnvelope resultEnvelope = new SoapEnvelope ();
resultEnvelope.parse (parser);
resultItem.setLabel ("amount :");
String result = (String)resultEnvelope.getResult();
result = result.substring(0,result.indexOf(".")+3);
resultItem.setText (" "+result);
os.close ();
reader.close ();
connection.close ();
}
catch (Exception e) {
resultItem.setLabel ("Error:");
resultItem.setText (e.toString ());
}
}
private static byte[] extractXml(byte[] extractFrom){
byte[] result;
int off=0;
boolean nonStop=true;
for(int i=0;nonStop;i++){
if (extra ctFrom[i]==60) {
off=i;
nonStop=false;
}
}
result=new byte[extractFrom.length -off];
for(int i=off;i<:extractFrom.length;i++){
result[i-off]=extractFrom[i];
}
return result;
}
}
Listing 3
MIDlet-1: FergieStock, , FergieStock
MIDlet-Jar-Size: 40598
MIDlet-Jar-URL: FergieStock.jar
MIDlet-Name: FergieStock
MIDlet-Vendor: Sun Microsystems
MIDlet-Version: 1.0
All Rights Reserved
Copyright © 2004 SYS-CON Media, Inc.
E-mail: info@sys-con.com
Java and Java-based marks are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries. SYS-CON Publications, Inc. is independent of Sun Microsystems, Inc.
|