You are on page 1of 36

THE LEADING DEVELOPER’S JOURNAL DEDICATED TO .

NET TECHNOLOGIES
Presented by

THE WORLD’S LEADING .NET RESOURCE

2007 Volume 5 Issue6

Dealing with
Legacy
Projects 10

Using XML with Stored


Procedures Effectively
in SQL Server 2005

Indexed LINQ A Roadmap


for Java Professionals
Register Today!
Early Bird: SAVE $100
Presorted
Standard
US Postage
PAID
St. Croix Press

W W W . D O T N E T D E V E L O P E R S J O U R N A L . C O M
2 June 2007 Volume: 5 Issue: 6 Visit us at www.dotnetdevelopersjournal.com
Editorial
EDITORIAL BOARD
Security, Vista and
the Developer
dotnetboard@sys-con.com
Editor-in-Chief
Patrick Hynds phynds@criticalsites.com

Group Publisher
Roger Strukhoff roger@sys-con.com
Mobility Editor
Jon Box jon.box@microsoft.com
Contributing Editor
Derek Ferguson derekf@speakeasy.net
Open Source Editor
Dennis Hayes dennisdotnet@yahoo.com
Product Review Editor
Doug Holland doug.holland@precisionobjects.com
VB Editor
Keith Franklin keithf@magenic.com
Smart Client Editor
Tim Huckaby timh@interknowlogy.com
BizTalk Editor
Brian Loesgen brian.loesgen@neudesic.com

Security Editor By Patrick Hynds


Duane Laflotte dlaflotte@criticalsites.com

ADVISORY BOARD
dotnetadvisors@sys-con.com

V
Derek Ferguson derekf@magenic.com ista is getting some traction
Jeremy Geelan jeremy@sys-con.com
Thom Robbins trobbins@microsoft.com as a client OS now and that
John Gomez John.Gomez@eclipsys.com
Scott Hanselman scott@hanselman.com
means developers are start-
Dean Guida deang@infragistics.com ing to see on the horizon that they
John Sharp johns@contentmaster.com
Jacob Cynamon jacobcy@microsoft.com should begin to support it. This is
Chris Mayo cmayo@microsoft.com good and bad. Good because there
Gary Cornell gary@thecornells.com
Joe Stagner joestag@microsoft.com are lots of cool things for develop-
Peter DeBetta peter@debetta.com
ers in Vista, but bad because Vista
Executive Editor changes the game quite a bit on
Nancy Valentine nancy@sys-con.com
developers relative to security.
SUBSCRIPTIONS On the good side Vista has lots
For subscriptions and requests for bulk orders,
please send your letters to Subscription Department more features and functionality,
Subscription Hotline: subscribe@sys-con.com such as the new firewall API and
Cover Price: $6.99/issue
Domestic: $69.99/yr. (12 issues) the introduction of gadgets; the
Canada/Mexico: $99.99/yr. Overseas: $129.99/yr.
(u.s. banks or money orders). Back issues: $12/ea.,
bad focuses mostly on trying to do things as a developer
plus shipping and handling. on Vista. Let me back up a bit. Security is good, of course,
EDITORIAL OFFICES but it is often the case that usability and security are in an
SYS-CON Media 577 Chestnut Ridge Rd.,
Woodcliff Lake, NJ 07677 inverse relationship. The more secure I make my house, the
Telephone: 201 802-3000 Fax: 201 782-9601 more likely I will end up calling a locksmith from my porch.
.NET Developer’s Journal (ISSN#1541-2849) is
published monthly (12 times a year) for $69.99 by Vista has User Access Control (also known as UAC), which
SYS-CON Publications, Inc., 577 Chestnut Ridge Road,
Woodcliff Lake, NJ 07677. prompts the user for permission to do anything that could
Postmaster: Send address changes to: be construed as above the norm security-wise. It turns out
.NET Developer’s Journal,
SYS-CON Publications, Inc., that pretty much everything a developer does is above the
577 Chestnut Ridge Road
Woodcliff Lake, NJ 07677.
norm security-wise, and that is a problem in a world where About the Author...
Copyright © 2007 by SYS-CON Publications, Inc. developers who don’t code on the target platform often get Patrick Hynds is the Microsoft Regional
All rights reserved. No part of this publication may be reproduced or
transmitted in any form or by any means, electronic or mechanical, killed for writing incompatible apps. This has resulted in a Director for Boston, the president of
including photocopy or any information storage and retrieval system,
without written permission. For promotional reprints, contact Reprint legion of developers that I know who have turned back or CriticalSites, and has been recognized as a
Coordinator Megan Mussa, megan@sys-con.com.
Worldwide Newsstand Distribution stopped at the brink of using Vista for their development. leader in the technology field. An expert on
Curtis Circulation Company, New Milford, NJ
Newsstand Distribution Consultant: You can turn off UAC and other features, but there is also the Microsoft technology (with, at last count, 55
Gregory Associates / W.R.D.S.
732 607-9941 - BJGAssociates@cs.com fact that older versions of Visual Studio (anything older than Microsoft certifications) and experienced
For list rental information:
Kevin Collopy: 845 731-2684, Visual Studio 2005, in fact) are not compatible or supported with other technologies as well, he previously
kevin.collopy@edithroman.com;
Frank Cipolla: 845 731-3832, on Vista. Even Visual Studio 2005 has issues as of this writing taught freelance software development and
frank.cipolla@epostdirect.com
All brand and product names used on these pages are trade names,
that some argue make it effectively unsupported. While the network architecture. Prior to joining Critical-
service marks, or trademarks of their respective companies. SYS-CON
Publications, Inc., is not affiliated with the companies or products latter will certainly resolve itself soon, the fact remains that Sites, Patrick was a successful contractor
covered in .NET Developer’s Journal. .NET and .NET-based marks are
trademarks or registered trademarks of Microsoft Corporation in the United if you target Visual Studio 2003 or earlier, then life is hard on who enjoyed mastering difficult troubleshoot-
States and other countries.
SYS-CON Publications, Inc., reserves the right to revise, republish and
Vista. Alternatives such as using virtual machines abound, ing assignments. A graduate of West Point
authorize its readers to use the articles submitted for publication.
but they all cost something in terms of productivity and and a Gulf War veteran, he brings an uncom-
sometimes sanity for the developer. mon level of dedication to his leadership role
Maybe this is just the price that we pay for notching up the at CriticalSites.
security of an operating system. Still it seems the developer
phynds@criticalsites.com
bears much more of the brunt than others...

Visit us at www.dotnetdevelopersjournal.com June 2007 Volume: 5 Issue: 6 3


Inside DNDJ
EDITORIAL

Security, Vista and the Developer


3
By Patrick Hynds ..........................................................................................................

MONKEY BUSINESS

Silverlight and Moonlight


By Dennis Hayes ..........................................................................................................7
Dealing with Legacy Projects
Do you COM?

By Catalin Sandu 10
INDEXES

Indexed LINQ
Optimizing the performance of LINQ queries using
in-memory indexes
By Aaron Erickson....................................................................................................... 28

Using XML with Stored Procedures PRODUCT REVIEW

Active Endpoints’ ActiveBPEL TM

Effectively in SQL Server 2005


How things changed
By Dennis Hayes ..........................................................................................................34
By Srinivas K. Surampalli 20

4 June 2007 Volume: 5 Issue: 6 Visit us at www.dotnetdevelopersjournal.com


BPEL
BPEL is
is the
the
������������
BPEL
SQL is
of the
SOA
SQL of SOA
the�������������
SQL of SOA
SOA

Get started building next-generation


SOAGet started building
applications next-generation
with the leading vendor of
SOAGet
applications
BPEL
started with
technologies
buildingthe leading vendor of
next-generation
Build next-generation
BPEL SOA applications
technologies
SOA applications with the leading vendor of
with the leader in BPEL technologies
Download BPEL BPEL technologies
tooling & server software today
generation
Download BPEL tooling & server software today
ding vendor of
������������������
es
������������������activeBPEL
Download BPEL tooling & server software today
active-endpoints.com/soa
������������������activeBPEL
er software today BPEL consulting and training.

activeBPEL
BPEL design tools, servers and source code for Eclipse, Apache Tomcat, JBoss,

����� WebSphere, BPEL

BPEL
Copyright
consulting
WebLogic,

WebLogic,
consulting
2006 Active
BizTalk
Endpoints,
and and
BizTalk

and
training.

and
Microsoft .NET.
BPEL design tools, servers and source code for Eclipse, Apache Tomcat, JBoss,
WebSphere, Microsoft .NET.
Inc. training.
All Rights Reserved.

activeBPEL
All product names are trademarks or service marks of their respective companies.
BPEL design tools, servers and source code for Eclipse, Apache Tomcat, JBoss, �
Copyright 2006 Active Endpoints, Inc. All Rights Reserved.
WebSphere,
All product WebLogic,
names are trademarks BizTalk
or service marksand Microsoft
of their respective .NET.
companies.

g. Copyright 2006 Active Endpoints, Inc. All Rights Reserved.


All product names are trademarks or service marks of their respective companies.
se, Apache Tomcat, JBoss,
Visit us at www.dotnetdevelopersjournal.com June 2007 Volume: 5 Issue: 6 5
rosoft .NET.
��������������������������������������

������������������������������������

�������������������������������������
�������������������������������������������

������������������������������������������������������������������
��������������������������������������������
������������������������������������������������������������������

���������������������������������� ������������������������������
����������������������������������������������������������������������
������������������������������������������������������������������������
�������������������������������������������

��������������������������������������
4 ��������������������������������������������������������
����������������������������������������
4 ����������������������������������������������������������������
�����������������������������������������������������
���������������������������
4 ����������������������������������������������������������
�������������������������������������������������������� ��������������������������������������������
���������������������
4 ������������������������������������������������

����������������������������������������������������������������
������������������������������������ ��������������
���������������������
�������������

�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������
�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������

6 June 2007 Volume: 5 Issue: 6 Visit us at www.dotnetdevelopersjournal.com


Monkey Business
Silverlight and Moonlight
By Dennis Hayes

M
icrosoft has a new set of technologies Moonlight, and the Silverlight homepages are at
called Silverlight that are meant to bring http://silverlight.net/ and http://www.microsoft.
rich multimedia to browsers and portable com/silverlight/. You can also see video of Moon-
devices. They have released two versions: a full re- light animation and video capture on Miguel’s
lease of version 1.0 and a beta version of 1.1. Version blog at http://tirania.org/blog/index.html (see
1.0 is not very interesting, but the 1.1 beta is totally the June 24 entries). Moonlight is being devel-
different and is making a big splash. oped as part of the Mono Olive Project (the Mono
It is .NET based, and of course Mono is working implementation of .NET 3.0). The implementa-
furiously on it. In fact, after Miguel saw Silverlight tion is now being discussed at http://groups.
for the first time at the Microsoft MIX 07 confer- google.com/group/mono-olive.
ence in Las Vegas and was offered the chance to There are a number of parts that combine to
demo Moonlight (the Mono version of Silverlight) form Silverlight, including a new security model
at Microsoft Re-MIX 07 in Paris in 21 days, the (see a good whitepaper at http://blogs.msdn.com/
whole Mono team started on a 21-day death march shawnfa/archive/2007/05/09/the-silverlight-secu-
to implement Moonlight in time to demo it in Paris. rity-model.aspx), video codecs, and a new version
After which, Miguel said of the .NET libraries labeled .NET 2.1 (aka WPF/E).
“The past 21 days have been some of the most .NET 2.1 is both a subset (similar to, but different
intense hacking days that I have ever had and the from, the compact framework), and a super set
same goes for my team that worked 12 to (adds libraries to support the new function-
16 hours per day every single day –in- ality); don’t even get me started on how
cluding weekends – to implement it relates to .NET 3.0 and 3.5.
Silverlight for Linux in record
time.” C#3.0
I know the long hard days Mono continues to work on
Miguel and the Mono team C#3.0 and this month brings full
typically work, and when he support for the specification for
starts talking about “the most implicitly typed local variables
intense hacking days” he has and implicitly typed arrays. I add-
ever had, part of me wishes I ed “for the specification” because
had been part of it, and part of the specification does not support
me is glad I wasn’t. implicitly typed multidimensional
What can a bunch of monkeys arrays, but the Microsoft C# 3.0 compiler
banging on a bunch of typewriters for 21 does support them; it is not clear if this is an
days create? The complete works of Shakespeare? enhancement or a bug; once this is decided, the
Nope. Check out Figure 1. Mono team will code accordingly.
Joshua Allen from Microsoft was impressed
with the Mono hack-a-thon and blogged about Google Summer of Code
it a bit at http://visitmix.com/ (see the June Students involved with the Google Summer of
21 entry). Note that Mono has not completed Code, including those working on Mono, are mak- About the Author
implementing the entire Silverlight suit, but the ing lots of progress. Google is having a major im- Dennis Hayes is a programmer at Georgia
screenshots show how much progress was made pact not only on these students’ lives, but also on Tech in Atlanta, Georgia, where he writes
in just 21 days. the many projects they are working on. I would like software for the Adult Cognition Lab in
For more screenshots, see http://www. to tell you all the cool things the students are doing the Psychology Department. He has been
mono-project.com/MoonlightShots. If you go just in the Mono project, but I don’t even have time involved with the Mono project for over five
to the bottom of the page and scroll up, you can for the highlights this month. Go check them out at years.
see how Moonlight progressed. The Moonlight http://groups.google.com/group/mono-soc-2007
homepage is at http://www.mono-project.com/ and http://planet-soc.com/. dennisdotnet@yahoo.com

Visit us at www.dotnetdevelopersjournal.com June 2007 Volume: 5 Issue: 6 7


Book Review

Amazon.com Top 10 .NET Books


President and CEO
Sams Teach Microsoft .NET
10 Yourself Microsoft
Visual Basic .NET
4 XML Web
Services Step by
Fuat Kircaali fuat@sys-con.com

Group Publisher
Roger Strukhoff roger@sys-con.com
2003 in 21 Days, Step
Second Edition Freeman, Adam
Holzner, Steve
ADVERTISING
Senior Vice President, Sales and Marketing
Carmen Gonzalez carmen@sys-con.com
MCAD/MCSD MCAD/MCSD Advertising Sales Director

Training Guide
(70-315):
3 Self-Paced
Training Kit:
Megan Mussa megan@sys-con.com
Associate Sales Manager

9
Corinna Melcon corinna@sys-con.com
Developing and Developing Web
Implementing Applications with Events Manager
Web Microsoft Visual Lauren Orsi lauren@sys-con.com
Events Associate
Applications with Visual C# and Basic .NET and Microsoft Visual
Sharmonique Shade sharmonique@sys-con.com
Visual Studio.NET C# .NET, Second Edition
Kalani, Amit Webb, Jeff

PRODUCTION
Lead Designer
MCAD/MCSD Abraham Addo abraham@sys-con.com

8 Self-Paced Programming
Art Director

2
Alex Botero alex@sys-con.com
Training Kit: Microsoft Associate Art Director
Developing Windows CE Louis F. Cuffari louis@sys-con.com
Assistant Art Director
Windows-Based .NET, Third Edition
Tami Lima Tami@sys-con.com
Applications with Boling, Douglas
Microsoft Visual Basic.NET and
Microsoft Visual C#.NET, Second
Edition WEB SERVICES
Stoecker, Matthew A. VP, Information Systems
Bruno Decaudin bruno@sys-con.com
Information Systems Consultant
Robert Diamond robert@sys-con.com
.NET and COM:
7 The Complete
Interoperability MCAD/MCSD Self-Paced
Web Designers
Stephen Kilmurray stephen@sys-con.com
Richard Walter richard@sys-con.com
Guide (2 Volume Training Kit: Microsoft .NET
Set) Core Requirements, Exams
Nathan, Adam

1 70-305, 70-315, 70-306,


70-316, 70-310, 70-320,
and 70-300 box vol. set
ACCOUNTING
Financial Analyst
Joan LaRose joan@sys-con.com
Microsoft Corporation Accounts Payable
Test-Driven Betty White betty@sys-con.com

6 Development
in Microsoft
.NET (Microsoft
Professional) SUBSCRIPTIONS
Newkirk, James W. 201 802-3012
888 303-5282
subscribe@sys-con.com

Programming

5 Microsoft Visual
Basic .NET
CUSTOMER RELATIONS
Circulation Service Coordinators
Version 2003 Edna Earle Russell edna@sys-con.com
Alicia Nolan alicia@sys-con.com
(Book & CD-
PROVIDED BY
ROM)
Balena, Francesco

8 June 2007 Volume: 5 Issue: 6 Visit us at www.dotnetdevelopersjournal.com


Figure 1: Silverlight-airlines-demo.png

MonoDevelop Banshee, the music player, now runs on Win-


MonoDevelop, the SharpDevelop fork for Mono, dows (screenshot at http://bp3.blogger.com/_
has released version 0.14. The MonoDevelop team vUUhoww_aGI/RnnZTn6WDSI/AAAAAAAAAOc/
has made a lot of progress on this release, and they G6lyyAmfS5Q/s1600-h/itsalive.jpg).
now plan to make two more big releases in the Mono has a list of what is needed to have com-
next three months, and then do a feature freeze to plete .NET 2.0 compatibility at http://www.mono-
prepare for the big version 1.0 release. This release project.com/Completing2.0Profile; currently the
includes a subversion add-in, refactoring, smart C# list is about 214 items long.
indenting, and importing/exporting Visual Studio Autosize is coming to System.Windows.Forms.
2005. The next releases are planned to include This is one of the biggest missing pieces
key binding, improved ASP.NET sup- left in Winforms; if you look through
port, and, from the Summer of Code the Moma reports, it appears
students, C/C++ support and im- very often, because VisualStu-
proved make file integration. Full dio sets it for most controls
release notes are at http://www. (to true or false depending
monodevelop.com/Release_ on the control).
notes_for_MonoDevelop_0.14. Also mojoPortal
2.2.2.8 has been released,
Facebook and Mono is again being
Tyler has posted information built from the same source
on how to use Mono to create code, but with a switch that
Facebook applications; see his turns off WebParts; see more
Weather# application example at at http://www.mojoportal.com/
http://www.unethicalblogger.com/ download.aspx.
posts/tyler/mono_meet_facebook. Brian Nickels shows how to make any
application a Web server at http://kerrick.word-
Odds and Ends press.com/2007/06/12/make-any-net-app-a-web-
Also Marcos Cobena (a summer of code student) server/.
has described how to compile Olive (.NET 3.0) on The last few columns have been so packed that
Mono at http://www.youcannoteatbits.org/Blog/ I have neglected to mention that the March issue
Archives/2007-April.html#Saturday%2c+April+21% began my fifth year of writing “Monkey Business”
2c+2007. for .NET Developer’s Journal .

“Microsoft has a new set of technologies


called Silverlight that are meant to bring rich
multimedia to browsers and portable devices”
Visit us at www.dotnetdevelopersjournal.com June 2007 Volume: 5 Issue: 6 9
Feature

Dealing with Legacy Projects


Do you COM?

By Catalin Sandu

Y
ou might be tempted to say that once you Why would a programmer do that? For one, there
About the Author enter the .NET world, you’ll never look are those old legacy projects your customers like
Catalin Sandu is a software developer at back. Nothing seems too easy for you at to use, and nothing can convince them (yet, you
RomSoft (www.rms.ro) and has 10 years of this moment, what with the brand-new .NET 3.0 hope) to upgrade to the latest and fastest platform
experience. He is both a Microsoft Certified that’s just out, high tech and still unexplored in its out there, thank you very much. Or if you’re among
Professional (on C++ and .NET) and an entirety. those lucky few whose clients are always eager
Advanced ColdFusion MX 7 Developer. However, there are situations in which the past to take the extra step and keep up with the latest
Catalin has also been a member of the Brit- catches up, raising the legitimate question of how technologies, maybe you still have some in-house
ish Computer Society since 2005. you can modify your existing .NET projects to allow projects (Visual Basic 6, anyone?) that are too com-
for interaction with the old Win32 programming plicated and would take a lot of time and money to
cat@rms.ro model. convert to your platform of choice.

10 June 2007 Volume: 5 Issue: 6 Visit us at www.dotnetdevelopersjournal.com


Feature
An elegant solution to these problems is to [assembly: ComVisible(true)]
expose your constructs as Component Object
Model (COM) objects that can be used without any The effect is that everything that’s written in the
problem from any Win32 program that can play .NET project will be exposed to the COM world.
with COM. The .NET platform allows you to do just Well, at least this is the short answer; the real story
that via a fancy intermediate object called COM will get revealed in a moment.
Callable Wrapper, or CCW, that sits between the The same thing can be accomplished if you go
COM client and your managed code. More on this to your project’s properties, select the Application
later. section, and then click on the “Assembly Informa-
This article will describe what it takes to expose tion” button. The last option in the dialog box
.NET components as COM objects. You’ll find that that appears is “Make assembly COM-visible,”
the job is not so difficult; in fact, most of the time and checking it will take care of changing the
what you’ll do is play with some new attributes that ComVisible attribute to true. Still, ComVisible has
would decorate your classes, class members, and other interesting uses as well, which you need to
methods. You’ll even learn how to create an Ac- understand if you have to master the COM game as
tiveX control in .NET, something that’s still hot off seen from a .NET vantage point. What’s the point of
Microsoft’s hands. But until then, let’s start with... getting everything for free if you don’t get your feet
wet, right?
The Basics Once you mark an assembly as being COM-vis-
The first thing we need for our purposes is, ible, everything inside can be accessed by COM
obviously, a normal, not COM-exposed .NET class, clients for free, but this is only partly true. What
which I’ll change into a COM-visible component. will actually get exposed is the stuff in the assembly
What’s more convenient than a hello-there-like that’s public. That’s right; all that’s private, pro-
component, like the one shown below: tected, or internal won’t see the COM light, ever. In
our hello-there sample, the private data member
public class HelloClass { _name is not exposed at all.
public string SayHelloTo(string person) { The same is true about all static methods and
_name = person; fields from your constructs. The list of things that
return “Hello there, “ + _name; won’t be accessible includes abstract classes,
} too. What’s more, your public data members will
private string _name; become properties for the new COM object. Did
} I mention that all types that really need to be ex-
posed should have a default constructor?
Before modifying this class for COM, I need to The ComVisible attribute, which can be used
do a quick detour and explain some of the theories on every possible level (assembly, class, structure,
involved in exposing a .NET class to a COM client. fields, methods, so on), comes in handy when
The framework component that is of help here is deciding which public parts of your library will get
called COM Callable Wrapper (CCW). This is the exposed. When using ComVisible(false) on a public
middleman that stays between your .NET compo- method, for example, it won’t be visible from COM
nent and the actual consumer. Every call to your clients. However, you can still use it from other
class will pass through this proxy, which will take .NET applications.
care of the usual COM behaviors for you, like refer- Now that you know how to play nice with COM,
ence counting. When the reference count reaches all that remains to be done is to... yes, you guessed
zero, the .NET object becomes a good candidate for it – register the resulting assembly in the Windows
the next round of the framework garbage-collec- Registry, so that other applications know about it
tion process. and use it. The next stop will be...
One more thing about CCW: unlike normal .NET
objects, the CCW is allocated from an uncollected The Registration Story: The .NET Way
heap. This is, in fact, the reason why the wrapper Normally, a COM library must be added to the
can be used from COM clients in the first place. The Windows Registry using the RegSvr32.exe utility.
CCW object is created on the fly, making everything Not so for .NET components. Remember, RegSvr32.
transparent for you, the .NET class designer. exe is used to register/unregister native Win32
Coming back to our hello-there class, the first DLLs and ActiveX controls, and won’t work on the
step in the COM-.NET dance is to mark your as- resulting .NET library.
sembly as being COM visible. For this, you need Enter the RegAsm.exe command line tool – or
to go to the AssemblyInfo.cs file for your project the Assembly Registration Tool. This small applica-
(assuming you’re writing a C# solution) and change tion will take a .NET component, read its metadata,
the ComVisible attribute from false (the default) to determine what constructs (classes, structures,
true, like this: so on) are marked as COM-visible, and write the

Visit us at www.dotnetdevelopersjournal.com June 2007 Volume: 5 Issue: 6 11


Feature

necessary entries in the registry. This friendly tool namespace This.Is.A.Very.Looong.Loooong.Namespace


is smart enough to do a little bit more than that, {
such as generating a type library for the exposed [ProgId(“My.Shorter.ProgID”)]
component, or creating a registry script containing public class MyClass {
the registration details. Neat, isn’t it? }
You might want to play with the tool to see what }
other options are available.
Assuming that our hello component compiles to Here, the default ProgID would have been This.
a Hello.dll library, here’s how you can register it: Is.A.Very.Looong.Loooong.Namespace.MyClass.
Now COM clients can consume this class using the
RegAsm.exe Hello.dll My.Shorter.ProgID programmatic identifier.
After registration, the component can be used
To verify that the component has been correctly from any Win32 application. However, there’s one
added to the Windows Registry, open the OleView more word to be added here. The recommended
tool. Expand the Grouped by Component Category way of registering a .NET library as a COM com-
node, then go to the .NET Category node. Now, ponent is to assign a strong name to your project,
assuming that the main namespace where the Hel- and then install the resulting DLL in the Global
loClass type has been defined is called Hello, you Assembly Cache (GAC). In fact, using the command
will find your COM object here (search for Hello. line that I’ve just shown assumes that Hello.dll will
HelloClass). eventually be added to the GAC.
To perform the reverse operation, all that’s If you really need to deploy the component in its
needed is to add the /unregister (or /u) switch to own folder and not place it in the Global Assembly
the above command line. Cache, you have to add the /codebase switch to the
If you’re not happy with the default program- command prompt when registering the assembly.
matic identifier generated for this class, there is This will result in an extra CodeBase entry in the
an alternative: just use ProgIdAttribute on your registry, pointing to the correct location of the re-
class. Normally, the programmatic identifier that sulting DLL. You can use this switch for debugging
gets written in the registry is composed of the purposes as well.
namespace where the class is defined and the Once the object has been correctly registered in
name of the class. This might result in a not-too- the Windows Registry, you can use it from any COM
easy to remember ProgID if the namespace chain client. For example, here’s how you can consume the
is too long. ProgIdAttibute takes care of this, giving Hello.HelloClass component from Visual Basic 6:
you control over this aspect too. Note that ProgIDs
are limited to 39 characters, including punctuation Dim obj As Object
(only dots are accepted.) To use this attribute, refer Set obj = CreateObject(“Hello.HelloClass”)
to the following snippet: MsgBox obj.SayHelloTo(“Jack”)
Set obj = Nothing

BUILT-IN .NET TYPE IDL EQUIVALENT C++ EQUIVALENT Pretty cool, right? While we’re at it, I can show
System.SByte (sbyte) char char how you can use the same .NET class from C++.
Since there’s a little bit more code involved in this
System.String (string) BSTR _bstr_t
case, I invite you to have a look at Listing 1 at the
System.Int32 (int) long long
end of this article (to keep things simple, error
System.Int64 (long) int64 __int64 checking was omitted from the code).
System.Byte (byte) unsigned char unsigned char You might wonder what customizations can be
made at register/unregister time, such as writing
System.Int16 (short) short short
additional registry entries or the like. The news is
System.UInt16 (ushort) unsigned short unsigned short
good in this matter, too – .NET defines two wonder-
System.UInt32 (uint) unsigned long unsigned long ful method-level attributes: ComRegisterFunction-
System.Char (char) unsigned short unsigned short Attribute and its counterpart ComUnregisterFunc-
System.UInt64 (ulong) uint64 unsigned __int64 tionAttribute. The methods on which they are used
will be called whenever the assembly is registered
System.Boolean (bool) VARIANT_BOOL VARIANT_BOOL
or unregistered:
System.Decimal (decimal) wchar_t DECIMAL
System.Single (float) single float public class HelloClass {
System.Double (double) double double ...code omitted...
System.Object (object) VARIANT _variant_t
[ComRegisterFunctionAttribute]
public static void RegisterHelloClass(Type t) {
Table 1 MessageBox.Show(“Registered type: “ +

12 June 2007 Volume: 5 Issue: 6 Visit us at www.dotnetdevelopersjournal.com


Feature
t.Name); in the System.Runtime.InteropServices namespace
} called RegistrationServices. This class contains a
[ComUnregisterFunctionAttribute] few useful methods that you might find interesting,
public static void UnregisterHelloClass(Type t) such as the possibility to enumerate all registerable
{ types from an assembly.
MessageBox.Show(“Unregistered type: “ + Isn’t it nice when you have such great flexibility
t.Name); at hand?
} Still, there’s a catch in all that I described so far.
} Things work as expected, that’s for sure, but have
you ever wondered why it works at all? The ques-
As shown above, the methods used with the two tion seems silly at first; in fact, this is exactly what
attributes must be static. You can apply both attri- those attributes are meant to do, right?
butes to the same method, but I don’t recommend Well, yes, but there is also a hidden face you
it unless you have a good reason to do so. There didn’t see. Each exposed type will automatically
can be more such methods in your code, one for get a few other attributes applied to them. It might
each class that gets exposed to COM, but you can’t help a project if you know a little bit more about
have more than one registration (or deregistration) this and will eventually lead to better designs. It’s
method for the same class. time to discuss the more serious stuff. It’s time to
I have to add here that all the functionality de- talk about...
scribed so far is also accessible in two other ways.
One is to check the “Register for COM Interop” Interfaces, Interfaces Everywhere...
option in the project properties. Note that the COM is all about implementing well-known or
component will be registered as if you were using custom interfaces, all of them ultimately deriv-
the /codebase switch in the Assembly Registration ing from the ubiquitously IUnknown interface
Tool. with its three methods: QueryInterface, AddRef,
The other method is to do it programmatically. and Release. Every .NET type that will eventually
The .NET Framework offers a special class for this be exposed to COM must emulate this somehow,

Shift Your Web Site Into Overdrive.


If you want powerful hosting at record-breaking speeds, go with the Gate.com team. We offer
state-of-the-art Windows hosting including ASP.NET 2.0 with free MS SQL servers, powerful
VPS solutions, rock-solid dedicated servers, robust Unix hosting, clustered servers, expert
24/7 phone support and much, much more. Get ready to put your Web site in the fast lane.

SHARED HOSTING VPS HOSTING


from
$ 95
9 /mo
from
$
29
95
/mo

Get your FIRST MONTH FREE* with no contract required.

Visit gate.com/ndj
Call 866.233.0602 and mention referral code 2402
*Offer valid for a limited time. Set-up fee may apply.

Visit us at www.dotnetdevelopersjournal.com June 2007 Volume: 5 Issue: 6 13


Feature

otherwise the .NET component won’t be of any use ing will explode. Here’s how it’s used:
for COM clients.
This is accomplished via ClassInterfaceAttrib- public class COMExposedClass {
ute, an attribute defined in the System.Runtime. [DispId(1000)] void DoSomething();
InteropServices namespace that can be applied to }
your classes. When used, ClassInterfaceAttribute
accepts a ClassInterfaceType argument that will Voilà! You have successfully created an AutoDual
establish the type of interface implemented by the class with set dispatch identifiers.
class. You can have a dual class interface (ClassIn- Let’s move on. What’s left for us is ClassInter-
terfaceType.AutoDual), a dispatch-only interface faceType.None. No class interface is generated if
(ClassInterfaceType.AutoDispatch), or a class you use this value, and you need to define your
for which you’ll implement your own interface own interfaces that will then be implemented by
(ClassInterfaceType.None). the exposed class. This offers the greatest flexibility
The default value used by .NET when the class from all values defined by ClassInterfaceType, and
is not marked with this attribute is AutoDispatch. is in fact the recommended way of exposing .NET
This means that the class implements the IDis- types to COM.
patch interface and supports late binding COM When defining interfaces that will later be imple-
clients only – that’s right, type information will not mented by a COM-visible .NET component, you
be generated for the exposed class, and its func- do it by giving it a Global Unique Identifier (GUID)
tionality can be discovered by calling IDispatch:: and specifying the interface type via yet another
GetIDsOfNames. Class methods will then be call- attribute (InterfaceTypeAttribute):
able via IDispatch::Invoke. This is exactly what I did
in Listing 1, and this is what happens behind the [Guid(“place-a-newly-generated-GUID-here”)]
scenes in the Visual Basic 6 snippet shown earlier. [InterfaceType(...a ComInterfaceType enumerated
The next enumeration value is AutoDual. This value goes here...)]
will generate a dual class interface for you. The public class ICoolInterface {
resulting component can be used both by late ...add some methods...
binding clients and by early binding COM clients. }
This might be wonderful, but let me spoil your
happiness before it’s too late: AutoDual has its own Note that the GUID attribute is optional – all
problems and its use is not recommended at all for types in .NET have a GUID associated with them,
good designs. but if you do want to control this aspect, this is the
Remember that the order of methods in a COM attribute you need.
interface is very important. You can’t reorder the ComInterfaceType is an enumeration that lets
methods inside an interface and live happily ever you define an IUnknown-derivative interface
after, especially when that piece of code is already (ComInterfaceType.InterfaceIsIUnknown), an IDis-
in production. A dual class interface needs its own patch-derivative interface (ComInterfaceType.In-
dispatch identifiers (DISPIDs) for the public stuff terfaceIsIDispatch), or a dual interface (ComInter-
defined for that class. This is exactly what AutoDual faceType.InterfaceIsDual), similar to ClassInterface
will do: it will automatically assign unique DISPIDs Type.
to your exposed methods, properties, public fields, Of course, you can implement non-COM visible
and so on. interfaces, too (just use ComVisible(false) when
Why is this bad news? A project is a living thing, defining them, or make them non-public). Obvi-
and as it evolves, you’ll find yourself redefining ously, these won’t be accessible to COM clients. See
classes, moving stuff around, and the next thing Listing 2 for a simple illustration of what I’ve just
you know, your DISPIDs are not the same anymore. described. It contains a class that implements an
Other .NET applications are quite happy with that, IUnknown-type interface, an IDispatch-type inter-
but this presents a real versioning problem for face (I omitted the GUID values from this code), as
already existing early binding COM clients, or cli- well as the class that implements them.
ents that have cached the initial dispatch identifier What if you need to implement a standard COM
values. interface? You’re in luck here, too. All you have to do
The basic advice here is to avoid using AutoDual is rewrite that interface in your solution and add an
at all costs, or to rely on it only if you don’t have any extra attribute, ComImport; it informs the frame-
other option. However, there might be a solution work that you’re bringing an outside interface into
for this after all: the ace up .NET’s sleeve is called your program. See Listing 3 for a possible definition
DispId (surprise!), which is a nice attribute that can of the well-known IOleCommandTarget interface (I
be applied to methods, fields, and properties. Thus, left the definition for OLECMD and OLECMDTEXT
even if you move things around, rest assured noth- for you as an exercise). Note that here you’re forced

14 June 2007 Volume: 5 Issue: 6 Visit us at www.dotnetdevelopersjournal.com


Feature
to use a GUID attribute, one whose value must be a TestTypes class. Now all I have to do is build and
the same as the one assigned by COM to the origi- register the resulting library (remember our friend,
nal interface. RegAsm.exe?).
That’s all I need to say about interfaces and Once the component is registered, you can use
classes for now. the OleView tool installed with Visual Studio to
Now, before moving to more interesting things, I browse for and look at the generated type library.
think we have to take another detour and see how All I did was apply the methods described in this
.NET types are mapping to COM data types. After article.
all, you need to know what other legacy project will
have to deal with when talking with your coolest Exposing Events
application ever. I promise to make it short. It’ll be Sooner or later you would need to expose some
only... events for your components. You’re already familiar
with .NET delegates and events, and you’re prob-
An Interlude: Mapping of .NET Built-in ably wondering if this knowledge can’t be leveraged
Types to Win32 Types in the COM world. True enough, this is exactly how
Table 1 shows which Interface Definition Lan- COM clients can respond to events happening in
guage (IDL) type corresponds to which .NET native your .NET code – plus a little help from an interme-
data type. Everything else (structures, for example) diate interface.
will build upon this table. Remember, IDL is the Remember our hello-there class from the begin-
language used to define COM interfaces (among ning of the article? I didn’t; it’s time to add some
others). For good measure, I included C++ types, event-exposing stuff to it. What if the powers that
too (there are slight variations between the two). be decide that your class can’t accept an empty
In fact, there is a very simple way to find out this string as parameter – after all, you can’t say hello
correspondence. Check out Listing 4; it defines an to nobody. An empty string parameter will trigger
ITestTypes interface that contains only dummy some kind of error in the code, and this can be
methods whose return types are exactly all .NET done in the form of an HelloError event.
built-in types. I then implemented this interface in To do it right from the COM point of view, the

�� ��
� ���������
��� ���
�� �����

�������������
���� ����
���������
� � ���
���������

������������
��

������������������������
ISBN 0-9777622-0-3

���������������
���������������������������������������
� � �������������������������������������������������������������������������������������
� ���������������������������������������������������������������������������������� �
���������������������������������������������

����
��������� ������� ������������������������
�����������������
from the Worldʼs Leading i-Technology Publisher © COPYRIGHT 2007 SYS-CON MEDIA

Visit us at www.dotnetdevelopersjournal.com June 2007 Volume: 5 Issue: 6 15


��
��� ��
Feature

event will be defined as a method in the intermedi- End Sub


ate interface that I told you about: Private Sub HelloObject_HelloError(ByVal hello_er-
ror As String)
[InterfaceTypeAttribute(ComInterfaceType.Interfa- MsgBox hello_error, vbOKOnly, “Error”
ceIsIDispatch)] End Sub
public interface IHelloEvents {
[DispId(0x00000001)] That’s it! You’re ready to build full-blown COM
void HelloError(string error); components from within Visual Studio and from
} your framework (and language) of choice.

Note that the interface derives from IDispatch The COM-Friendly User Controls: Ex-
(required when exposing events to COM), and that posing ActiveX Functionality from .NET
I’ve thrown my own DISPID for the only interface You might think that once you know all about the
method. HelloError accepts a string parameter COM-related attributes from the .NET Framework,
– this might be useful if the design requires that all it would be very simple to implement an ActiveX
errors from HelloClass need to be self-describing. control. After all, what’s in an ActiveX control? You
To use this new interface, all I need to do now is need to implement this and that interface and de-
to add it as a COM source interface to HelloClass. pending on what functionalities your control needs
Here’s the new implementation for the hello-there to support, you might want to add some events and
class: you’re ready to go.
Indeed, the UserControl class that sits at the base
[ComSourceInterfaces(typeof(IHelloEvents))] of every control defined by you ultimately imple-
public class HelloClass : IHello { ments a series of standard COM interfaces that
...implementation goes here... are pretty much mandatory for an ActiveX control:
} IOleControl, IOleWindow, IViewObject, and so on
– it really looks like all the hard work has already
Note again that the class has been changed a been done for you.
little bit from what I wrote at the beginning of the Not so fast. Although Microsoft has given a lot
article. See Listing 5 for all the implementation of thought to the interoperability game, ActiveX
details. I’ve created an IHello interface, dropped has somehow disappeared from the list. Yes, this
the useless _name data member, and then imple- scenario is not supported at all, and, until recently,
mented the IHello interface via HelloClass. you were on your own if you needed to build such
There’s a reason why I derived my IHello inter- a beauty. Up to a (fragile) point, this really could
face from IDispatch in this listing; I want to show be done, but there was no guarantee that things
you how to use HelloClass from the old Visual Basic wouldn’t start behaving erratically exactly when
6, and VB6 can’t consume IUnknown objects. Of you were ready to uncork the champagne.
course, making IHello an AutoDual interface will I just lied to you: there was in fact just one single
do just fine, too. scenario available to you. If you really like to play
The VB6 demo program will look pretty much with a hot potato, you could develop ActiveX
like the one shown below. I assume you’re dealing controls hosted inside Internet Explorer 5.01 and
with an application containing one single form later. There are many things to be considered here,
with two buttons called HelloJack and HelloNo- all depending on your project needs – security is-
body. Clicking on either button will call the SayHel- sues, deployment, and so on. If all went fine, your
loTo method from HelloClass. Don’t forget to add a UserControl objects could be brought up on an
reference to the COM object you have just created. HTML page via the well-known OBJECT tag. The
IE hosting scenario for .NET controls is quite a big,
Dim WithEvents HelloObject As HelloClass complex subject, and I won’t go further on this
Private Sub Form_Load() road.
Set HelloObject = New HelloClass As an aside, what I just said was true for .NET
End Sub 1.0; starting with 1.1, the framework lets you use
Private Sub Form_Unload(Cancel As Integer) Windows Forms from Visual C++ projects using
Set HelloObject = Nothing Microsoft Foundation Classes (MFC), plus Internet
End Sub Explorer 5.01 or later.
Private Sub HelloJack_Click() I said that you couldn’t create regular ActiveX
MsgBox HelloObject.SayHelloTo “Jack”, vbOKOnly, controls. Well, things have changed lately. The
“Hello” new kid in town is called Microsoft Interop Forms
End Sub Toolkit, now in its second release, and available
Private Sub HelloNobody_Click() from http://msdn2.microsoft.com/en-us/vbasic/
HelloObject.SayHelloTo “” bb419144.aspx.

16 June 2007 Volume: 5 Issue: 6 Visit us at www.dotnetdevelopersjournal.com


Feature
This is a free add-in for Visual Studio (actually, control no matter what; be advised though that the
for Visual Basic 2005) that will help you create toolkit has been created with VB6 in mind, and you
window forms and user controls ready to be used should test your project carefully before going live
from Visual Basic 6. You read it perfectly: officially, with it.
the toolkit supports only VB.NET-to-VB6 scenarios. It’s been a long ride and now we’re going for
In its first release (September 2006), the Interop the home stretch. I’m sure there is enough here to
Toolkit allowed VB6 applications to display .NET make you interested in exploring other .NET-COM
Windows Forms easily. Exposing UserControls as interoperability issues. For now, I have to summa-
ActiveX components was still in beta at that time, rize everything up in a nice...
but the last release (May 2007) adds full support for
creating such controls from VB.NET, too. Conclusion
Once the toolkit is installed, you’ll end up with I’ve only touched the tip of the iceberg in this
two additional project templates for VB.NET: one article about the .NET and COM playground.
for building user controls that are visible from VB6 There are still the issues of deployment to dis-
(the InteropUserControl template) and one to al- cuss, or what happens with classes that inherit
low VB6 programs to use a Windows Form (the VB6 from ComVisible ones, and which are exposed
InteropForm template). There is also a very good themselves to COM. Also, there are some issues
documentation with plenty of tutorials, as well as a when having overloaded methods; for example,
series of sample projects. if you have SomeMethod defined twice, what you
Since the toolkit already comes with all that, I get is a COM class whose second method is re-
won’t insist on this subject more than is neces- named to SomeMethod_2; this is a real problem
sary. I leave it to you to explore the powerful toys for VB6, which doesn’t recognize methods with
contained in this kit. underscores in their names.
I have to say a few more things here. Although Anyway, your toolbox now contains one more
the toolkit is intended to work with VB6 projects, secret when dealing with legacy applications. This
you can still use the resulting ActiveX controls from can be the beginning of a beautiful friendship
any COM client. An ActiveX control is an ActiveX between you and those old projects.

// The result will be stored here


LISTING 1: CALLING A .NET COMPONENT FROM C++ VARIANT vtRes;
// Initialize the COM system ::VariantInit(&vtRes);
::CoInitialize(NULL); // Invoke the method
// Retrieve the CLSID for Hello.HelloClass lpDispHello->Invoke(
CLSID clsidHello; dispSayHelloTo, IID_NULL, LOCALE_SYSTEM_DEFAULT,
LPOLESTR szHello = L”Hello.HelloClass”; DISPATCH_METHOD, &dispparams, &vtRes, NULL, NULL);
::CLSIDFromProgID(szHello, &clsidHello); // Here vtRes.bstrVal is equal to “Hello there, Jack”
// Create the IDispatch instance // Get rid of our component
LPDISPATCH lpDispHello = NULL; lpDispHello->Release();
::CoCreateInstance( // Don’t forget to uninitialize COM
clsidHello, NULL, CLSCTX_INPROC_SERVER, ::CoUninitialize();
IID_IDispatch, (LPVOID*)&lpDispHello);
// Retrive the DISPID for the SayHelloTo method LISTING 2: A CLASSINTERFACETYPE.NONE CLASS
LPOLESTR szHelloFn = L”SayHelloTo”; IMPLEMENTING TWO INTERFACES
DISPID dispSayHelloTo; using System.Runtime.InteropServices;
lpDispHello->GetIDsOfNames( namespace Test {
IID_NULL, &szHelloFn, 1, LOCALE_SYSTEM_DEFAULT, &dispSay- /// <summary>
HelloTo); /// Define an interface derived from IUnknown
// Prepare the parameters for the SayHelloTo method /// </summary>
DISPPARAMS dispparams = { NULL, NULL, 0, 0 }; [Guid(...), InterfaceType(ComInterfaceType.InterfaceIsI-
dispparams.cArgs = 1; Unknown)]
dispparams.rgvarg = new VARIANT[dispparams.cArgs]; public interface IInterfaceOne {
dispparams.cNamedArgs = 0; void TestMethodOne();
dispparams.rgvarg[0].vt = VT_BSTR; }
dispparams.rgvarg[0]. bstrVal = ::SysAllocString(OLESTR(“J /// <summary>
ack”)); /// Throw in another interface, derived from IDispatch...

Visit us at www.dotnetdevelopersjournal.com June 2007 Volume: 5 Issue: 6 17


Feature

/// </summary> [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]


[Guid(...), InterfaceType(ComInterfaceType.InterfaceIsI- public interface IOleCommandTarget {
Dispatch)] [PreserveSig()]
public interface IInterfaceTwo { int QueryStatus(ref Guid pguidCmdGroup, uint cCmds,
void TestMethodTwo(); [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=1)]
} OLECMD[] prgCmds, ref OLECMDTEXT pCmdText);
/// <summary> [PreserveSig()]
/// And yet another interface, this time an internal one. int Exec(ref Guid pguidCmdGroup, uint nCmdID, uint nC-
/// Even if it is defined with InterfaceIsIUnknown, it mdExecOpt,
/// will not be exposed to COM, because it is internal. ref object pvaIn, ref object pvaOut);
/// </summary> }
[Guid(...), InterfaceType(ComInterfaceType.InterfaceIsI- LISTING 4: CLASS USED TO DISCOVER THE CORRE-
Unknown)] SPONDENCE BETWEEN .NET TYPES AND COM TYPES
internal interface INotExposedInterface { using System.Runtime.InteropServices;
void SomeMethod(); namespace Test {
} [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
/// <summary> public interface ITestTypes {
/// This class is defined as ClassInterfaceType.None, and string GetAString();
/// implements our interfaces. All members defined by int GetAnInt();
/// these interfaces (except INotExposedInterface, of long GetALong();
course) sbyte GetSByte();
/// are exposed to COM clients. All other methods defined byte GetByte();
in short GetShort();
/// this class are NOT exposed at all, even if they are ushort GetUShort();
public. uint GetUInt();
/// That is, ClassInterfaceType.None is used for a class char GetChar();
/// that will expose only ComVisible interfaces to the ulong GetULong();
outside bool GetBool();
/// world. All other methods and members are not exposed. decimal GetDecimal();
/// </summary> float GetFloat();
[ClassInterface(ClassInterfaceType.None)] double GetDouble();
public class TestClass : object GetAnObject();
IInterfaceOne, IInterfaceTwo, INotExposedInterface { }
// This method IS exposed, because it comes [ClassInterface(ClassInterfaceType.None)]
// from the IInterfaceOne interface public class TestTypes : ITestTypes {
public void TestMethodOne() {} public string GetAString() { return string.Empty; }
// This method IS exposed, because it comes public int GetAnInt() { return Int32.MaxValue; }
// from the IInterfaceTwo interface public long GetALong() { return Int64.MaxValue; }
public int TestMethodTwo() {} public sbyte GetSByte() { return SByte.MaxValue; }
// This method, even if implements the method public byte GetByte() { return Byte.MaxValue; }
// with the same name from INotExposedInterface public short GetShort() { return short.MaxValue; }
// will not be exposed because that interface public ushort GetUShort() { return ushort.MaxValue; }
// is marked as internal. public uint GetUInt() { return uint.MaxValue; }
public void SomeMethod() {} public char GetChar() { return char.MaxValue; }
// This method IS NOT exposed, because it is public ulong GetULong() { return ulong.MaxValue; }
// defined by a class marked as ClassInterfaceType.None, public bool GetBool() { return true; }
// and doesn’t come from a ComVisible interface. public decimal GetDecimal() { return decimal.MaxValue;
public void InvisibleMethod() {} }
} public float GetFloat() { return float.MaxValue; }
} public double GetDouble() { return double.MaxValue; }
public object GetAnObject() { return null; }
LISTING 3: THE DEFINITION FOR THE IOLECOMMAND- }
TARGET STANDARD INTERFACE }
[ComVisible(true), ComImport()]
[Guid(“B722BCCB-4E68-101B-A2BC-00AA00404770”)] LISTING 5: EXPOSE EVENTS TO COM

18 June 2007 Volume: 5 Issue: 6 Visit us at www.dotnetdevelopersjournal.com


using System.Runtime.InteropServices;
namespace Test {
public delegate void HelloErrorHandler(string error);
Advertiser Index
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] ADVERTISER URL PHONE PG
public interface IHello {
Active Endpoints active-endpoints.com/soa 5
string SayHelloTo(string name);
}
ESRI www.esri.com/develop 1-888-288-1277 6
[InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIDispatch)]
public interface IHelloEvents {
[DispId(0x00000001)] Gate.com www.gate.com/ndj 866-233-0602 13
void HelloError(string error);
}
Microsoft defyallchallenges.com 36
[ClassInterface(ClassInterfaceType.None)]
[ComSourceInterfaces(typeof(IHelloEvents))]
Real-World AJAX Book www.realworldajaxbook.com 201-802-3020 15
public class HelloClass : IHello {
event HelloErrorHandler HelloError;
public string SayHelloTo(string name) { Real-World Java Seminar www.realworldjava.com 201-802-3020 29
string realName = name.Trim();
if (realName != string.Empty) {
Software FX www.softwarefx.com 561-999-8888 35
return “Hello there, “ + realName;
}
Verio www.verio.com/dotnetdoneright 888-Verio33 2
if (HelloError != null) {
HelloError(“No one out there?”); General Conditions: The Publisher reserves the right to refuse any advertising not meeting the standards that are set to protect the high edito-
} rial quality of .Net Developer’s Journal. All advertising is subject to approval by the Publisher. The Publisher assumes no liability for any costs
or damages incurred if for any reason the Publisher fails to publish an advertisement. In no event shall the Publisher be liable for any costs or
return string.Empty; damages in excess of the cost of the advertisement as a result of a mistake in the advertisement or for any other reason. The Advertiser is fully
responsible for all financial liability and terms of the contract executed by the agents or agencies who are acting on behalf of the Advertiser.
} Conditions set in this document (except the rates) are subject to change by the Publisher without notice. No conditions other than those set forth
} in this “General Conditions Document” shall be binding upon the Publisher. Advertisers (and their agencies) are fully responsible for the content
of their advertisements printed in .Net Developer’s Journal. Advertisements are to be printed at the discretion of the Publisher. This discretion
} includes the positioning of the advertisement, except for “preferred positions” described in the rate table. Cancellations and changes to adver-
tisements must be made in writing before the closing date. “Publisher” in this “General Conditions Document” refers to SYS-CON Publications,
Inc. This index is provided as an additional service to our readers. The publisher does not assume any liability for errors or omissions.

Active Endpoints’ ActiveBPEL –continued from 34

It also includes APIs to access and con- WebSphere capabilities. Security can be Future
trol the inner workings of the BPEL engine. handled by the Tivoli Access manager or by The difference between BPEL and
The J2EE and .NET integrated versions legacy or third-party security solutions. Ac- workflow is that BPEL focuses on auto-
add multi-level load balancing and server tiveBPEL also supports all of the WebSphere mating Web services, where workflow
fault tolerance and deep integration into clustering capabilities including automatic focuses on connecting people-oriented
each of the supported servers: .NET, Web- failover and content-based routing. processes. Active Endpoints has recently
Sphere, JBoss, and WebLogic. On JBoss, ActiveBPEL uses the Axis released ActiveBPEL for People, which
In the .NET version, BPEL processes can JAX-RPC for Web services invocations extends BPEL to include people-oriented
be launched via either the IIS server API, and message exchange, and also allows tasks, including roles and Web-based
or a native .NET API. Access security can direct control by the JBoss WS4EE or EJB user interfaces.
be handled by either IIS or ASP.NET-based bindings. It also integrates with JBossSX
security, allowing access list to be stored in security or LDAP servers. ActiveBPEL sup- More Information
a database, Active Directory, or third-party ports all of the JBoss clustering technology, For more information, checkout Active
security suites. Also, ActiveBPEL can be in- including JGroups and the Tomcat Http- Endpoints’ Web site at http://www.ac-
stalled in an IIS Web farm where a wide range Session object to provide load balancing, tive-endpoints.com/, there is a nice slide
of load balancing strategies can be used. failover, and single sign-on. show at http://www.bptrends.com/pub-
The WebSphere version can run as a WS-I Truly the people at Active Endpoints under- licationfiles/BPEL4ProgArchies.pdf, and
compliant framework, or inside WebSphere stand how important it is to use and integrate Wikipedia has a page on BPEL at http://
containers to take advantage of advanced with the different platforms they run on. en.wikipedia.org/wiki/BPEL.

Visit us at www.dotnetdevelopersjournal.com June 2007 Volume: 5 Issue: 6 19


Feature

Using XML with Stored Procedures


Effectively in SQL Server 2005
How things changed
By Srinivas K. Surampalli

N
ET lets us easily serialize an object into XML the Stored Procedure, we’d use XQuery against the
and deserialize XML into its corresponding passed XML to extract the desired data. This elimi-
. object. This functionality has been avail- nates multiple parameters to the Stored Procedure
able since .NET 1.0. The introduction of new data and minimizes the Stored Procedure calls to the
type called XML in SQL Server 2005 gives us even database.
more advantages that come in handy with Stored
Procedures that attempt to insert/update records in XML Serialization Primer
multiple but related tables. XML Serialization is the process of converting an
Usually this involves passing a huge number of object’s public Properties and Fields (the current
parameters that make up the individual objects to state of the object) into an XML stream; likewise,
the Stored Procedure; but with SQL Server 2005 we XML deserialization is the process of creating an
could potentially serialize the object(s) into an XML object from an XML to a state as specified by the
string and pass it as the input parameter, leaving us XML stream.
with cleaner code that’s easy to read and maintain. XML serialization comes in two flavors – when
Consider the case of having a Person object with an object is serialized, its properties could either be
list of Address and Phone objects. The correspond- expressed as ‘Xml-Elements’ (default) or as ‘Xml-
ing database schema would have tables for Person, Attributes’ in the XML output. Consider a simple
Address, and Phone. When a new Person is inserted class called “Book” as shown in Listing 1. Code to
into the database (along with the corresponding serialize an instance of “Book” into XML and dese-
About the Author address and phone number), generally we’d have to rialize the XML into another instance of “Book” is
Srinivas K. Surampalli alias Kal is a senior pass all the member variables of the Person object shown in Listing 2. Serialized XML for an instance
consultant at Magenic Technologies. He has to a Stored Procedure and, if successful, call other of Book is shown in both formats in Listing 3.
over a decade of experience in delivering Stored Procedures to insert the records into the Ad- Note that you would need a default constructor
innovative technology solutions to busi- dress and Phone tables. for the class for the XmlSerializer to serialize and
nesses using Microsoft Technologies. He is I propose an alternate way of doing the same deserialize. Also note that for an instance of an ob-
a MCSD for Microsoft.NET and Microsoft thing that’s a lot simpler. Suppose we serialize ject, only those properties are serialized that have a
Visual Studio 6.0. When not working, Kal the Person object along with its list of Address non-null value.
enjoys playing with his two children Avyay and Phone objects into XML; this XML parameter The XmlSerializer class (defined in the
and Anagha. would then be passed to the Stored Procedure namespace System.Xml.Serialization) is used for
which could handle the inserts to the Person, serialization and deserialization processes. As
kals@magenic.com
Address, and Phone tables all by itself; and within you can see, Xml-Element model is verbose when

20 June 2007 Volume: 5 Issue: 6 Visit us at www.dotnetdevelopersjournal.com


Feature
compared to the XmlAttribute model. In this article that of the property) and each patient is listed with
we’ll consider the XmlAttribute model. As you’ve the XML node “Patient” that is the same as the class
seen, to get the output in Xml-Element format, name for the Patient class.
we don’t have to do anything since it’s the default We’ve seen the snippet of code that does serial-
behavior; on the other hand, for the XmlAttribute ization and deserialization in Listing 3. However
model, we have to annotate the public properties this code snippet is specific to the “Book” class. To
and public fields with XmlAttributes. generalize the code for serialization and dese-
To control the generated XML, we could apply spe- rialization, we could define these functions in
cial XML Attributes to the class or the public fields a common base class. Let’s define a class called
and public properties. Attributes provide additional “BusinessBase” that could serve as a base class to
information to the XmlSerializer class on how the all business objects. This class could then have two
data appears in XML. Here are a few important at- functions – ToXML() for serialization and FromX-
tributes to consider: ML() for deserialization. This way, any business
object like Person, Doctor, Patient, Phone, Address,
XmlAttributeAttribute: XmlAttributeAttribute (or etc. could automatically leverage this functionality.
just XmlAttribute) should be applied to the public Code for BusinessBase is shown in Listing 6.
properties and fields of the class that you want to Notice the Copy() function that serves as a Copy
be serialized as attributes (as opposed to elements). Constructor (deep copy). This is needed since the
This article recommends using attributes model Deserialize() function of XmlSerializer returns an
for XML serialization. Listing 1 below already offers object that has to be copied into ‘this’ again. Use
an idea of how one model compares to the other. of these functions is shown in Listing 7, assuming
It shows how XmlAttribute is declared for proper- that we’ve derived the class “Book” from “Business-
ties. The name given for the attribute is the same Base.”
as we see in the XML output. Generally we’d have We’ve already defined the “Person” class. Let’s
the same name as the Property itself. However, if add collections to this class, one for the address
desired, we could change this as shown in Listing 5 list and the other for the phone list. To do this, we
for the class “Patient” for the property “MRN” that need two classes called “Address” and “Phone.”
would be serialized as “Medical_Record_Number.” Listing 8 below shows the “Address” and “Phone”
Note: When specifying an Attribute, the phrase classes along with the part of the “Person” class that
‘Attribute’ could be omitted from the name of the reflects the change.
attribute since .NET would recognize the attribute. Note that we have defined enums “AddressType”
This is true for all Attributes and not just XML attri- and “PhoneType” to enumerate different types of
butes. This is the reason why XmlAttributeAttribute addresses and phones respectively. These enums
can be specified as simply XmlAttribute. have to be kept in synch with the data defined in
the database tables “AddressType” and “Phone-
XmlRootAttribute: XmlRootAttribute (or just Type.”
XmlRoot) decorates the class itself. It specifies how
the root element would be displayed in XML. If this XmlIgnoreAttribute: We’ve already said that by
isn’t specified, the name of the class would appear default, all public properties and fields of a class
as-is, as the root element. Usually we don’t have are serialized; if any of these have to be omitted,
to set this attribute. However, there may be a case we need to annotate the desired properties/fields
where the class name may not be suitable as the with the attribute XmlIgnoreAttribute or in short,
root name in the serialized XML. This can happen XmlIgnore.
when the class name differs from the name used in Omitting certain data from serialization could
business parlance. For instance, let’s say we have a
class called “Doctor”; by default, this would appear
as the root in the serialized XML. But, if users like to
see the root name as “Physician” instead of “Doc-
tor” we need to set the XmlRoot attribute for the
class as “Physician.” This is shown in Listing 4.

XmlArrayItemAttribute: When we have to serial-


ize a collection XmlArrayItemAttribute comes in
handy. Consider the case of a “Doctor” having a list
of patients as a Property. Listing 5 shows the Patient
class and a property in the Doctor class called
“Patients,” which is decorated with the attribute
XmlArrayItemAttribute. Note the XML output that Figure 1: Database schema for Person with Address
lists the XML node as “Patients” (the same name as and Phone information

Visit us at www.dotnetdevelopersjournal.com June 2007 Volume: 5 Issue: 6 21


Feature

prove handy if you want to serialize only a select set without any exceptions then control doesn’t enter
of properties. As seen in Listing 8, we have two prop- the CATCH block at all. As seen in Listing 10, at the
erties for the field _addrType: AddrType and Ad- end of the TRY block, we commit the transaction
dressTypeId; the former an ‘AddressType’ type and and return the error code (0=success) and the ID
latter of ‘int’ type. In the XML output, we need the of the inserted “Person” record; whereas, in the
property to be expressed as ‘int’ since that’s how it’s CATCH block, we roll back the transaction and
expressed in the database (AddressType table). The return the error code and error message.
other property need not be serialized to XML, which XQuery or XML Query Language is a W3C speci-
is why it’s annotated with the attribute XmlIgnore. fication on how XML could be queried. XQuery
The corresponding database schema for these specification document could be found at http://
classes would be as shown in Figure 1. www.w3.org/TR/xquery/.
Now, to insert a Person record along with its The value() and nodes() are the XML data type
Address records and Phone records in one Stored methods in SQL Server 2005. Other methods avail-
Procedure all we have to do is serialize the Person able, but not used in this article are query(), exist(),
object and pass the XML to the Stored Procedure. and modify().
In the Stored Procedure, we’d use XQuery to parse The nodes() method returns an unnamed row-
the XML and extract the data as needed. set, which is why it’s aliased in CreatePerson SP as
Listing 9 shows the code snippet that instanti- seen in Listing 10. The value() method extracts the
ates a Person object along with its Address and value of the node from the rowset with the type
Phone collections, and the corresponding XML specified. Note that it can extract multiple values
representation of the Person instance. if the rowset returned by the nodes() method con-
The Stored Procedure “CreatePerson” could be tains multiple values. This is how multiple address
seen in Listing 10. or phone records could be inserted with just one
Notice the use of TRY-CATCH blocks in the INSERT statement.
Stored Procedure. From SQL Server 2005 onwards, As you’ve seen in this article, using XML saves
this is the preferred way to catch any errors dur- us from passing multiple parameters to the Stored
ing the execution of a Stored Procedure; in earlier Procedure, and it facilitates inserting records into
versions, global parameter @@ERROR was used to multiple/linked tables cleanly. Later, if the object
retrieve the code of the last error when executing a properties change or tables get modified, the input
SQL statement, and “GO TO” statements had to be to the Stored Procedure doesn’t have to change,
used to modify the control flow. Using TRY-CATCH and could continue to be XML; the Stored Proce-
block eliminates this to write cleaner code; if an dure itself would have to be changed to reflect the
exception does get raised in a TRY block during changes, but the caller wouldn’t have to modify the
the execution, control automatically jumps to the input parameters to the Stored Procedure. So code
CATCH block where the appropriate error-handling maintenance is easier since minimal changes have
code could be placed. If Stored Procedure executes to be made.

LISTING 1 DEFINITION OF A “BOOK” CLASS /// Author of the Book


FOR BOTH FORMATS /// </summary>
Book definition for Xml-Elements model Book defi- private string _author;
nition for XmlAttributes model public string Author
Notice how each property in the class is deco- { get { return _author; }
rated with XmlAttribute. set { _author = value; } }
public class Book
{ /// <summary>
/// <summary> /// Default constructor: Needed for Xml
/// title of the book serialization
/// </summary> /// </summary>
private string _title; public Book() { }
public string Title
{ get { return _title; }
set { _title = value; } } /// constructor
public Book(string title, string isbn,
/// <summary> string author)
/// ISBN of the book {
/// </summary> Title = title;
private string _isbn; ISBN = isbn;
public string ISBN Author = author;
{ get { return _isbn; } }
set { _isbn = value; } } }
public class Book
/// <summary> {

22 June 2007 Volume: 5 Issue: 6 Visit us at www.dotnetdevelopersjournal.com


Feature
/// <summary> // Following code would deserialize xml into
/// title of the book Book object
/// </summary> // get the byte stream from the string in utf-8
private string _title; encoding
[XmlAttribute(“Title”)] Byte[] bytes = encoding.GetBytes(xml);
public string Title
{ get { return _title; } // create a stream from the bytes
set { _title = value; } } memoryStream = new MemoryStream(bytes);

/// <summary> Book deserializedBook = serializer.Deserialize(m


/// ISBN of the book emoryStream) as Book; //Deserialization
/// </summary>
private string _isbn; LISTING 3 SERIALIZED XML FOR AN IN-
[XmlAttribute(“ISBN”)] STANCE OF A “BOOK” CLASS
public string ISBN XML-Element format XML-Attribute format
{ get { return _isbn; } <?xml version=”1.0” encoding=”utf-8” ?>
set { _isbn = value; } } <Book xmlns:xsi=”http://www.w3.org/2001/
/// <summary> XMLSchema-instance” xmlns:xsd=”http://www.
/// Author of the Book w3.org/2001/XMLSchema”>
/// </summary> <Title>Visual C# 2005 A Developer’s Note-
private string _author; book</Title>
[XmlAttribute(“Author”)] <ISBN>0-596-00799-X</ISBN>
public string Author <Author>Jesse Liberty</Author>
{ get { return _author; } </Book> <?xml version=”1.0” encoding=”utf-8”
set { _author = value; } } ?>
<Book xmlns:xsi=”http://www.w3.org/2001/XMLSche-
/// <summary> ma-instance”
/// Default constructor: Needed for Xml xmlns:xsd=”http://www.w3.org/2001/XMLSchema”
serialization Title=”Visual C# 2005 A Developer’s
/// </summary> Notebook” ISBN=”0-596-00799-X” Author=”Jesse
public Book() Liberty” />
{
} LISTING 4 DEFINITION OF A “DOCTOR”
CLASS AND A “PATIENT” CLASS
/// constructor Class definition for Doctor Class definition for
public Book(string title, string isbn, Patient
string author) [XmlRoot(“Physician”)]
{ public class Doctor : Person
Title = title; {
ISBN = isbn; private string _specialization;
Author = author; [XmlAttribute(“Specialization”)]
} public string Specialization
{ get { return _specialization; }
} set { _specialization = value;}}

private List<Patient> _patients =


LISTING 2 CODE TO SERIALIZE AND DESE- new List<Patient>();
RIALIZE [XmlArrayItem(typeof(Patient))]
Book book = new Book(“Visual C# 2005 A Develop- public List<Patient> Patients
er’s Notebook”, { get { return _patients; }
“0-596-00799-X”, “Jess set { _patients = value;}}
Liberty”);
XmlSerializer serializer = new /// <summary>
XmlSerializer(book.GetType()); /// default constrcutor
/// </summary>
MemoryStream memoryStream = new MemoryStream(); public Doctor(){}
XmlTextWriter writer = new XmlTextWriter(memoryS
tream, Encoding.UTF8); // constructor
serializer.Serialize(writer, book); public Doctor
( string fName,
// get the stream from the writer string lName,
memoryStream = writer.BaseStream as MemoryS- string specialization
tream; ) : base(fName, lName)
{
// apply encoding to the stream Specialization = specialization;
UTF8Encoding encoding = new UTF8Encoding(); }
string xml = encoding.GetString(memoryStream.
ToArray()).Trim(); // function to add a patient
public void AddPatient(Patient patient)

Visit us at www.dotnetdevelopersjournal.com June 2007 Volume: 5 Issue: 6 23


Feature

{ using System.Xml.Serialization;
Patients.Add(patient);
} namespace DNDJ_XmlSerialization
{
//function to remove a patient public class BusinessBase
public void RemovePatient(Patient pat) {
{ /// <summary>
Patients.Remove(pat); /// function to copy all properties from bBase-
} ToCopy into ‘this’(Copy Constructor)
} /// </summary>
public class Patient : Person /// <param name=”bBaseToCopy”></param>
{ public virtual void Copy(BusinessBase bBaseTo-
private string _mrn; Copy)
[XmlAttribute(“Medical_Record_Number”)] {
public string MRN // get all the properties from ‘this’
{ PropertyInfo[] properties = this.GetType().
get { return _mrn; } GetProperties();
set { _mrn = value; }
} // loop through the properties
foreach (PropertyInfo property in proper-
private string _diagnosis; ties)
[XmlAttribute(“Diagnosis”)] {
public string Diagnosis if (property.CanWrite && property.Can-
{ Read) // if there is a Set & Get Method
get { return _diagnosis; } {
set { _diagnosis = value; } //Invoke the “set” on ‘this’ and
} “get” on ‘bBaseToCopy’
property.GetSetMethod().Invoke(this,
/// <summary> new object[] { property.GetGet-
/// default constructor Method().Invoke(bBaseToCopy, null) });
/// </summary> }
public Patient(){} }
}
//constructor
public Patient /// <summary>
( string fName, /// Function to convert ‘this’ into XML string.
string lName Could be overridden in derived class
) : base(fName, lName) /// if desired. we use UTF-8 encoding since
{ SqlServer would understand only UTF-8
} /// </summary>
/// <returns></returns>
} public virtual string ToXML()
{
LISTING 5 SERIALIZED XML FOR AN IN- // create a memory stream/text writer for
STANCE OF A “DOCTOR” CLASS UTF-8 encoding (1-char 1-byte)
<?xml version=”1.0” encoding=”utf-8” ?> MemoryStream memoryStream = new MemoryS-
<Physician tream();
xmlns:xsi=”http://www.w3.org/2001/ XmlTextWriter writer = new XmlTextWriter(mem
XMLSchema-instance” xmlns: oryStream, Encoding.UTF8);
xsd=”http://www.w3.org/2001/XMLSchema”
FirstName=”Austin” LastName=”Szubryt” Specializa // create the serializer and serialize
tion=”Paediatrics”> ‘this’
<Patients> XmlSerializer serializer = new
<Patient FirstName=”Malcom” LastName=”Speed” XmlSerializer(this.GetType());
Medical_Record_Number=”M555678999” serializer.Serialize(writer, this);
Diagnosis=”Burns” />
<Patient FirstName=”Amit” LastName=”Jain” // get the stream from the writer
Medical_Record_Number=”M333875452” memoryStream = writer.BaseStream as MemoryS-
Diagnosis=”Shortness of breath” /> tream;
</Patients>
</Physician> // apply encoding to the stream and return
the string
LISTING 6 BUSINESSBASE CLASS DEFINI- UTF8Encoding encoding = new UTF8Encoding();
TION string xml = encoding.GetString(memoryStream.
using System; ToArray()).Trim();
using System.IO;
using System.Reflection; // strip out the first line; we do not need
using System.Text; it.
using System.Xml; xml = xml.Replace(“<?xml version=\”1.0\”

24 June 2007 Volume: 5 Issue: 6 Visit us at www.dotnetdevelopersjournal.com


REPRINT IT!
encoding=\”utf-8\”?>”, string.Empty);
return xml;
}

/// De-serializer: Hydrates an object from the xml; We use UTF-8


encoding since
/// SqlServer would understand UTF-8 format only.
/// </summary>
/// <param name=”xml”></param>
/// <returns></returns>
public void FromXML(string xml)
{
// get the byte stream from the string in utf-8 encoding
UTF8Encoding encoding = new UTF8Encoding();
Byte[] bytes = encoding.GetBytes(xml);

// create a stream from the bytes


MemoryStream memoryStream = new MemoryStream(bytes);

// create a serializer and de-serialize ‘this’


XmlSerializer serializer = new XmlSerializer(this.GetType());

// finally call copy constructor to copy the deserialized out-


put into ‘this’
this.Copy(serializer.Deserialize(memoryStream) as Business-
Base);
}

}
}

LISTING 7 USING TOXML() AND FROMXML() FUNCTIONS


Book book = new Book(“Visual C# 2005 A Developer’s Notebook”,
“0-596-00799-X”, “Jesse Liberty”);

string xml = book.ToXML(); // Serialization


Book deserializedBook = new Book();
book.FromXML(xml); //Deserialization

LISTING 8 DEFINITION OF THE ADDRESS AND PHONE CLASS-


ES WITH A PARTIAL DEFINITION OF PERSON CLASS
Definition of AddressType and Address Definition of PhoneType and
Phone
public enum AddressType
{
Home = 1,
Work = 2
}

public class Address : BusinessBase


{
private int _addressId = -1; // default
[XmlAttribute(“AddressId”)]
public int AddessId
{ get { return _addressId; }
set { _addressId = value;}}

private string _line1;


[XmlAttribute(“Line1”)]
public string Line1
{ get { return _line1; }
set { _line1 = value;}}

private string _line2;


[XmlAttribute(“Line2”)]
public string Line2
{ get { return _line2; }

Visit us at www.dotnetdevelopersjournal.com June 2007 Volume: 5 Issue: 6 25


Feature

set { _line2 = value;}} public PhoneType PhoneTypeId


{ get { return _phType; }
private string _city; set { _phType = value;}}
[XmlAttribute(“City”)]
public string City // default constructor
{ get { return _city; } public Phone() {}
set { _city = value;}} }

private string _state; public class Person : BusinessBase


[XmlAttribute(“State”)] { private int _personId = -1; // default
public string State [XmlAttribute(“PersonId”)]
{ get { return _state; } public int PersonId
set { _state = value;}} { get { return _personId; }
set { _personId = value;}}
private string _zipCode;
[XmlAttribute(“ZipCode”)] private List<Address> _addresses = new
public string ZipCode List<Address>();
{ get { return _zipCode; } [XmlArrayItem(typeof(Address))]
set { _zipCode = value;}} public List<Address> Addresses
{ get { return _addresses; }
private AddressType _addrType; set { _addresses = value;}}
[XmlIgnore()]
public AddressType AddrType private List<Phone> _phones = new
{ get { return _addrType; } List<Phone>();
set { _addrType = value;}} [XmlArrayItem(typeof(Phone))]
public List<Phone> Phones
[XmlAttribute(“AddressTypeId”)] { get { return _phones; }
public int AddressTypeId set { _phones = value;}}
{ get { return ...}
Convert.ToInt32(_addrType); }
set {_addrType = (AddressType)value;} LISTING 9 SERIALIZING PERSON WITH AD-
} DRESSES AND PHONES
Person person = new Person(“John”, “Doe”);
// default constructor
public Address() { } Address addr1 = new Address();
} public enum PhoneType addr1.Line1 = “124 Highland Ave.”;
{ addr1.Line2 = “Suite 234”;
Home = 1, addr1.City = “Lombard”;
Work = 2, addr1.State = “IL”;
Mobile = 3, addr1.ZipCode = “60148”;
} addr1.AddrType = AddressType.Work;

public class Phone : BusinessBase person.AddAddress(addr1);


{
private int _phoneId = -1; // default Address addr2 = new Address();
[XmlAttribute(“PhoneId”)] addr2.Line1 = “3456 Main St.”;
public int PhoneId addr2.City = “Naperville”;
{ get { return _phoneId; } addr2.State = “IL”;
set { _phoneId = value;}} addr2.ZipCode = “60563”;
addr2.AddrType = AddressType.Home;
private int _areaCode;
[XmlAttribute(“AreaCode”)] person.AddAddress(addr2);
public int AreaCode
{ get { return _areaCode; } Phone phone1 = new Phone();
set { _areaCode = value;}} phone1.AreaCode = 800;
phone1.PhoneNumner = 1234567;
private int _phoneNumber; phone1.PhType = PhoneType.Work;
[XmlAttribute(“PhoneNumber”)]
public int PhoneNumner person.AddPhone(phone1);
{ get { return _phoneNumber; }
set { _phoneNumber = value;}} Phone phone2 = new Phone();
phone2.AreaCode = 630;
private PhoneType _phType; phone2.PhoneNumner = 5481234;
[XmlIgnore()] phone2.PhType = PhoneType.Home;
public PhoneType PhType
{ get { return _phType; } person.AddPhone(phone2);
set { _phType = value;}} string xml = person.ToXML();
<Person xmlns:xsi=”http://www.w3.org/2001/
[XmlAttribute(“PhoneTypeId”)] XMLSchema-instance” xmlns:xsd=”http://

26 June 2007 Volume: 5 Issue: 6 Visit us at www.dotnetdevelopersjournal.com


Feature
www.w3.org/2001/XMLSchema” PersonId=”-1” SELECT newPerson.value(‘@FirstName’, ‘var-
FirstName=”John” LastName=”Doe”> char(50)’) FirstName,
<Addresses> newPerson.value(‘@LastName’, ‘var-
<Address AddressId=”-1” Line1=”124 High- char(50)’) LastName
land Ave.” Line2=”Suite 234” City=”Lombard” FROM @personXML.nodes(‘/Person’)
State=”IL” ZipCode=”60148” AddressTypeId=”2” /> node(newPerson)
<Address AddressId=”-1” Line1=”3456 Main St.” SET @personId = @@IDENTITY -- note down the
City=”Naperville” State=”IL” ZipCode=”60563” Ad- Id of the inserted record
dressTypeId=”1” />
</Addresses> -- insert records into Address table (mul-
<Phones> tiple possible)
<Phone PhoneId=”-1” AreaCode=”800” PhoneNum- INSERT INTO dbo.Address(PersonId, AddressTy-
ber=”1234567” PhoneTypeId=”2” /> peId, Line1, Line2, City, State, Zipcode)
<Phone PhoneId=”-1” AreaCode=”630” PhoneNum- SELECT @personId,
ber=”5481234” PhoneTypeId=”1” /> newAddr.value(‘@AddressTypeId’, ‘int’)
</Phones> AddressTypeId,
</Person> newAddr.value(‘@Line1’, ‘varchar(50)’)
Line1,
LISTING 10 DEFINITION OF STORED PROCE- newAddr.value(‘@Line2’, ‘varchar(50)’)
DURE CREATEPERSON Line2,
set ANSI_NULLS ON newAddr.value(‘@City’, ‘varchar(50)’)
set QUOTED_IDENTIFIER ON City,
go newAddr.value(‘@State’, ‘varchar(50)’)
State,
-- sample xml of Person object newAddr.value(‘@ZipCode’, ‘int’) Zipcode
/*** FROM @personXML.nodes(‘/Person/Addresses/Ad-
<Person xmlns:xsi=”http://www.w3.org/2001/ dress’) node(newAddr)
XMLSchema-instance” xmlns:xsd=”http://www.
w3.org/2001/XMLSchema” -- insert records into Phone table (multiple
PersonId=”-1” FirstName=”John” LastName=”Doe”> possible)
<Addresses> INSERT INTO dbo.Phone(PersonId, PhoneTypeId,
<Address AddressId=”-1” Line1=”124 High- AreaCode, PhoneNumber)
land Ave.” Line2=”Suite 234” City=”Lombard” SELECT @personId,
State=”IL” ZipCode=”60148” AddressTypeId=”2” /> newPhone.value(‘@PhoneTypeId’, ‘int’)
<Address AddressId=”-1” Line1=”3456 PhoneTypeId,
Main St.” City=”Naperville” State=”IL” Zip- newPhone.value(‘@AreaCode’, ‘int’) Area-
Code=”60563” AddressTypeId=”1” /> Code,
</Addresses> newPhone.value(‘@PhoneNumber’, ‘int’)
<Phones> PhoneNumber
<Phone PhoneId=”-1” AreaCode=”800” PhoneNum- FROM @personXML.nodes(‘/Person/Phones/
ber=”1234567” PhoneTypeId=”2” /> Phone’) node(newPhone)
<Phone PhoneId=”-1” AreaCode=”630” PhoneNum-
ber=”5481234” PhoneTypeId=”1” /> -- now that all inserts have been completed,
</Phones> commit the transaction
</Person> COMMIT TRANSACTION CREATE_PERSON
***/
-- return the error code followed by the Id
CREATE PROCEDURE [dbo].[CreatePerson] of the inserted Person record
( SELECT ISNULL(ERROR_NUMBER(), 0) ErrorCode,
@personXML XML @personId
)
END TRY -- end of TRY block
AS
BEGIN BEGIN CATCH -- control would come here only in
-- SET NOCOUNT ON added to prevent extra re- case of an exception
sult sets from -- since an exception has ocurred, rollback
-- interfering with SELECT statements. the transaction
SET NOCOUNT ON; IF @@TRANCOUNT > 0
DECLARE @personId INT -- saves the value of ROLLBACK TRANSACTION CREATE_PERSON
the inserted Person record’s Id
-- error has ocurred; return error number
BEGIN TRY --begin the TRY block and err_msg to the caller
SELECT ISNULL(ERROR_NUMBER(), 0) ErrorCode,
-- wrap the multiple inserts in a ERROR_MESSAGE() ErrorMessage
Transaction END CATCH -- end of CATCH block
BEGIN TRANSACTION CREATE_PERSON END -- end of SP

-- insert the new person record


INSERT INTO dbo.Person(FirstName, LastName)

Visit us at www.dotnetdevelopersjournal.com June 2007 Volume: 5 Issue: 6 27


Indexed LINQ

Indexed LINQ
Optimizing the performance of LINQ queries using in-memory indexes

By Aaron Erickson

L
anguage Integrated Query (LINQ) is a very Indexing to the Rescue
powerful new technology coming to us with Nearly any searching algorithm is better than
Visual Studio 2008. There is a great deal of sequential search. Of course, to use any of those
innovation going on in the LINQ space, including algorithms, we have to know a little bit more about
innovative projects like LINQ-to-Flickr and LINQ- what we are searching. If your items are in order,
to-Amazon (among many others), in addition to the you might use a binary search, which would help
great things Microsoft is providing in LINQ-to-SQL quite a bit. However, for the best possible perfor-
and LINQ-to-XML. mance, you want your search to use an index – just
This article dives deeper into the more mundane like every relational database worth mentioning
details about how to optimally query data you does when it searches through a large collection of
already have in memory via LINQ-to-Objects. LINQ rows.
lets you do queries on any object (typically col-
lections or arrays) that support IEnumerable<T>. Implementation of a Generic Index
For example, if you have an online bookstore, you As it turns out, we need three elements to be
might decide to cache your products in memory able to do this in a generic manner:
on the Web server to improve performance. In such • An ability to easily specify which fields in a class
a case, you might have a List<Books> bookCache we are going to have an indexed collection of
that you query this way when someone goes to look that we are going to index.
up a book: • A mechanism that allows for building and main-
taining these indexes automatically.
var searchResult = from b in bookCache • Modification of the implementation of Where so
where b.ISBN=”978-1590596326” that it takes advantage of the index, rather than
select b; doing a sequential search.

Now, imagine your cache of books for your Web The [Indexable()] Attribute
site contains, say, a million books, and you need to If we’re going to have an easy-to-use indexing
make this scale in a serious way. In such a case, you mechanism, we need a simple way to answer the
might be interested in optimizing how LINQ works. “what” question – as in what is it we are going to
build indexes on. Building indexes on every property
How LINQ Queries in Memory Objects in a class is almost certainly going to be too much
About the Author When you use LINQ syntax to do a query, what – causing performance lags when you build the col-
Aaron Erickson is a principal consultant really happens is that the syntax is converted lection, not to mention wasting memory if we build
for Magenic. He is a ruthless advocate for to a series of method calls, such as where, join, indexes on fields that aren’t searched on. To be more
concentrating on creating the most business and others related to the query “operators” that specific about what we are going to index, we need
value in the least amount of time when his LINQ supports. Of interest to us is, for purposes to add some meta-information to our class. That’s
clients entrust him to deliver a technical solu- of a query, how Microsoft implements “Where” exactly what Attributes are for.
tion. Aaron has been delivering solutions on in LINQ to Objects. Given that Where has to work Thankfully, for a simple indexing implementa-
the Microsoft platform for over 14 years, and for any IEnumerable<T>, there’s very little that tion, we need nothing more than to mark certain
currently leads open source development the default implementation can do to optimize properties as indexable. The implementation of the
efforts related to LINQ, including Indexes the query. As a result, the default search over attribute is very simple:
of Objects (i4o) and LINQ to Expressions IEnumerable<T> in LINQ is a sequential search.
(MetaLinq). In other words, if you are searching for the book public class IndexableAttribute : Attribute { }
at the bottom of a million-book pile, your search
aarone@magenic.com may not be terribly fast. Once in place, we can do the following with any

28 June 2007 Volume: 5 Issue: 6 Visit us at www.dotnetdevelopersjournal.com


���������������
���������������������
���������������������

����������
����������������������

���������������

�������������������
�������������

�������������������
���������������������������
�����������������������
— Sponsored by —
�������������������������������������������������������������������������������������������������
����������������������������������������������������������������������������������������������
������������������������������������������������������������������������������������������������������
�����������������������������������������������������������������������������������������������
����������������������������

— Produced by —
�����������������������

For this and other great events


������������������������
� ����������������� ������������������������
visit www.EVENTS.SYS-CON.com ��������������������
������������������������������
� ��������������������
��������������������������� �������������� ����������������
��������������� ��������������������
��������������������������
�������������������������������
� ��������������������������
�������
���������������������
����������������������������
� ���������������
����������������������
���������������������

©COPYRIGHT 2007 SYS-CON MEDIA The Java Coffee Cup logo and Sun logos are trademarks of Sun Microsystems

Visit us at www.dotnetdevelopersjournal.com June 2007 Volume: 5 Issue: 6 29


Indexed LINQ

class we intend to use in an indexed collection: associates them with the appropriate inner list. For
example, the inner list might hold everything that
class Book starts with “A.” The outer list might hold 26 items,
{ one for each letter (a list for “A,” a list for “B,” and so
private string _isbn; forth). When you look up an item, you would look
private string _authorFirstName; up by its first letter, find the list to look in, and then
private string _authorLastName; search through the smaller list, rather than search-
private int _id; ing through everything. Our data structure for a
particular index looks like this:
[Indexable()]
public string ISBN { get { return _isbn; } Dictionary<int, List<T>>
set { _isbn = value; } }
In our actual implementation, we’ll look up
[Indexable()] by int rather than string for the index. We use int
public int Id { get { return _id; } set { because int is what the GetHashCode() method
_id = value; } } returns from all objects in .NET. One of the keys
to making this work is that all objects support
public string AuthorFirstName { GetHashCode() – which lets us, while not uniquely
get { return _author- identify an object, effectively parti-
FirstName; } tion it into very small groups.
set { _authorFirstName Of course, there may be more
= value; } than one index in our collection. So
} in actuality, our implementation will
use a Dictionary of indexes, which
[Indexable()] gives us the following structure in
public string AuthorLast- the end:
Name {
get { return _author- protected Dictionary<string,
LastName; } Dictionary<int, List<T>>> _indexes
set { _authorLastName = = new Dictionary<string,
value; } Dictionary<int, List<T>>>();
}
} Building the indexes on the construction of the
collection is the next step. When we build a new
Implementation of IndexableCollection<T>, we need to reflect what
IndexableCollection<T> we’re collecting, find out which properties are
The next step is to have a collection that, while going to be indexed (by looking for the presence
based on the collection functionality that .NET of the IndexableAttribute), and create the index
gives us, lets us intercept certain operations on accordingly. The following routine, called from the
it that are of interest to maintaining an index. constructor, accomplishes that goal:
Namely, we want, at the very least, to know when
something is added or removed from the collec- protected void BuildIndexes()
tion. {
To start, we’ll derive from Collection<T>, from PropertyInfo[] allProps = typeof(T).Get-
System.Collections.ObjectModel, as follows: Properties();
foreach (PropertyInfo prop in allProps)
public class IndexableCollection<T> : {
Collection<T> object[] attributes = prop.GetCustomAt
{ tributes(true);
foreach (object attribute in attri-
} butes)
if (attribute is IndexableAttrib-
Build the Index ute)
The first thing we need is a structure to hold our _indexes.Add(prop.Name, new
indexes. An index can be defined as a sort of “dic- Dictionary<int, List<T>>());
tionary of lists.” The inner list holds everything that }
relates to a certain indexed value. The outer dic- }
tionary holds all the different indexed values and

30 June 2007 Volume: 5 Issue: 6 Visit us at www.dotnetdevelopersjournal.com


Indexed LINQ
Intercept Collection Adds We need to make these public since anything
Once indexes are built, you need a mechanism to that might want to implement an index on this is
add data to the indexes (and eventually remove it). going to need to be able to see if a property has
In our implementation, we’re going to redefine the an index and retrieve the index if a given index
Add method in our collection: exists.

public new void Add(T newItem) A Smarter Where Implementation


{ At this point, we have an indexed collection that
foreach(string key in _indexes.Keys) could, in theory, be used by a query processor to
{ enable faster searches based on lookups rather
PropertyInfo theProp = typeof(T). than searching sequentially (a k a associative
GetProperty(key); search). Which brings us to our next problem – how
if (theProp != null) do we write our own implementation of Where?
{ The answer is a new C# 3.0 feature called Exten-
int hashCode = theProp. sion Methods. While explaining how extension
GetValue(newItem, null).GetHashCode(); methods work is a topic worthy of its own article,
Dictionary<int, List<T>> index = for purposes of this exercise, we can say that exten-
_indexes[key]; sion methods let us extend classes we don’t own to
if (index.ContainsKey(hashCode)) do things we want them to do. Extending our own
index[hashCode].Add(newItem); class to have its own custom where implementa-
else tion, as it turns out, isn’t terribly difficult. To do
{ so, you create a static class, with a static Where
List<T> newList = new method that contains a special signature:
List<T>(1);
newList.Add(newItem); public static class IndexableCollectionExten-
index.Add(hashCode, newList); tion
} {
} //extend the where when we are working
} with indexable collections!
base.Add(newItem); public static IEnumerable<T> Where<T>
} (
this IndexableCollection<T> sourceCol-
The mechanics of Add are to iterate through the lection,
known indexes, and using reflection, retrieve the Expression<Func<T, bool>> expr
hash code of the appropriate property value for each )
field on the object we’re going to index. Once we
have that value (hashCode above), we look in the in- Extension methods extend the class you specify
dex to see if we have an entry yet for that hash code. in the first parameter, the one shown here with the
If we do, we simple add the item to the list of entries modifier on the parameter. The second param-
that have the given hash code. If not, we create a new eter is the actual parameter that a Where method
entry in that index based on the hash code. is always passed – namely, the expression we’re
Once we’re done, we call the Add routine in the going to evaluate to determine whether we do an
base class so that we have the normal behavior of index lookup or simply pass the call through to the
add implemented. We can now go ahead and add a
couple of helper methods that would help anyone
trying to implement an index:

public bool PropertyHasIndex(string propName)


{
return _indexes.ContainsKey(propName);
}

public Dictionary<int, List<T>> GetIndexByProp


erty(string propName)
{
return _indexes[propName];
}
Figure 1:

Visit us at www.dotnetdevelopersjournal.com June 2007 Volume: 5 Issue: 6 31


Indexed LINQ

default implementation of where. BinaryExpression binExp =


(BinaryExpression)expr.Body;
Analyzing the Expression Tree
Expressions are a representation of code as data Examine the Left Side
– something very familiar to those from the LISP Once we know we’re dealing with a binary
world. The Where method takes an Expression as “equals” expression in the body of the lambda, we
its parameter, allowing the implementer of where can determine whether we’re dealing with a field
to determine how a search is going to take place. that is indexable. We pass the left side of our binary
In LINQ-to-SQL this is where the expression is expression to the following method:
converted to SQL code that is, in turn, passed to
the database. However, in our case, rather than do private static bool HasIndexablePropertyOnLef
a conversion, we’re simply going to examine the t<T>(
tree to determine if we can use an index, and if so, Expression leftSide,
figure out what to look up. IndexableCollection<T> sourceCollection)
Two conditions must be true for us to be able to {
use an index. if (leftSide.NodeType == ExpressionType.
MemberAccess)
• The where clause must be testing for equality return sourceCollection.PropertyHasIn-
• The property on the left-hand side of the com- dex(
parison must be a field we happen to have an ((MemberExpression)leftSide).Member.Name
index for. );
else
Is Where Testing for Equality? return false;
Our test to determine whether the programmer }
is doing an equality operation is not as complex as
it might seem. A Where always gets a certain type of This routine performs two important tests. The
expression passed to it called a LambdaExpression. first is to see if it’s the kind of expression we can
LambdaExpressions are simply delegates assigned use on the left side – something called a Member-
to a data structure. In our case the LambdaExpres- Expression. MemberExpressions are expressions
sion tends to be a specialized version that always that relate to any property lookup that might occur
returns a Boolean value by virtue of being part of a in code. We need the expression to be a member
where clause. expression because that’s the only type that will let
Lambda expressions have two main properties us determine which index, if any, to use.
– a set of Parameters that reflect the parameters The second test, which only applies if it is, in
that go into the lambda, and a Body that represents fact, a MemberExpression, is to make sure that
what the lambda actually does (see Figure 1). Of the property that the MemberExpression tries
particular interest to us is the Body expression. to access is, in fact, indexed by the collection
Specifically, we want to make sure that: we’re working with. To perform this test, we use
a. The expression is, in fact, a BinaryExpression the PropertyHasIndex method we wrote earlier,
b. And that the BinaryExpression represents an passing the name of the property the user
“equals” operation passed into the query. If this works, we know we
The following code does both for us: have a field for which an indexed lookup is pos-
sible.
if (expr.Body.NodeType == ExpressionType.Equal)
{ Evaluate the Right Side
//Equality is a binary expression Now that we know what index to use, we need to

“As anyone who has ever done work with


databases knows, indexes can provide
dramatic performance improvements for
large sets of data.”
32 June 2007 Volume: 5 Issue: 6 Visit us at www.dotnetdevelopersjournal.com
Indexed LINQ
figure out the value that we’ll be looking up in the foreach (T item in result)
index. So we need to figure out what value the right yield return item;
side of the BinaryExpression (a k a the right side of }
the equals) evaluates to. Unlike the left side, we’re noIndex = false; //we found an index
less picky about what might be on the right side of
the expression. The right side could be a constant The process of doing an indexed lookup is a
number, a string, or any other valid C# statement matter of calling Where again, this time, on a much
that evaluates to something. The following routine smaller set – the items within a given page of the
does the evaluation: index – rather than the entire enumeration. The
results of the where are then iterated through, us-
private static int? GetHashRight(Expression right- ing the yield return statement on each item as you
Side) would with any other iteration routine.
{ In case no index is found, you simply do the fol-
//rightside is where we get our hash... lowing:
switch (rightSide.NodeType)
{ if (noIndex) //no index? just do it the normal
//shortcut constants, dont eval slow way then...
case ExpressionType.Constant: {
ConstantExpression constExp IEnumerable<T> sourceEnum = sourceCollection.
= (ConstantExpression)rightSide; AsEnumerable<T>();
return (constExp.Value.GetHashCode()); IEnumerable<T> result = sourceEnum.
default: Where<T>(expr.Compile());
LambdaExpression evalRight = foreach (T resultItem in result)
Ex.Lambda(rightSide, null); yield return resultItem;
//Compile it, invoke it, and get the }
resulting hash
return evalRight.Compile(). This does nothing more than return results just
DynamicInvoke(null). like the default where implementation does – look-
GetHashCode(); ing at each element of the collection and checking
} to see if it passed the test in the expression passed
} to the Where method.

For constant nodes – which could be an int, Results


string, or some other data structure, we go ahead As anyone who has ever done work with data-
and simply grab the value, get its hash, and return bases knows, indexes can provide dramatic per-
that. For other nodes, we convert the expression formance improvements for large sets of data.
to a LambdaExpression, compile it, invoke the re- Over a large set of a million books, our lookup
sulting method, and get our hash from the result. time would have been around 1,200ms for the
Either way, so long as the result isn’t null, we’ll unfortunate book at the end of the collection.
get an int lookup value we can use for our index Using an index, however, brings that time down
lookup. to less than 10ms – a 100x performance im-
provement.
Do the Query But it’s not without a cost. The code to main-
Once we have a property we know we have tain an index in cases where the values of the ob-
an index and a value to look up in the index, we jects change more frequently is somewhat more
can go ahead and process the query using the complex, requiring you to implement a change
index: notification in the class you’ll be indexing. And
just like database indexes, adding indexes slows
hashRight = GetHashRight(rightSide); down your add, remove, and update operations
Dictionary<int, List<T>> myIndex = – making the developer who has domain knowl-
sourceCollection.GetIndexByProperty(prope edge of how the objects will be used the only
rty); person who can possibly know the best indexing
if (myIndex.ContainsKey(hashRight.Value)) strategy.
{ The source code that ties all of this together
IEnumerable<T> sourceEnum = myIndex[hashRight. is available at www.codeplex.com/i4o, an open
Value].AsEnumerable<T>(); source project designed to make indexed col-
IEnumerable<T> result = sourceEnum. lections available to all developers on the .NET
Where<T>(expr.Compile()); platform.

Visit us at www.dotnetdevelopersjournal.com June 2007 Volume: 5 Issue: 6 33


Product Review

Active Endpoints’ ActiveBPEL


TM

Using and integrating different platforms


By Dennis Hayes

What Is BPEL?
BPEL or Business Process Execution Language is an
XML and Web standards–based SOA (service-oriented ar-
chitecture) standard that allows business people to com-
bine services into automated processes. As described in
this review, Active Endpoints’ ActiveBPEL product family
includes a visual designer that works by allowing non-
programmers to assemble Web services into processes
by dragging and dropping graphical representations of
components (Web services) and “wiring” them together
in sequences and flowcharts (see Figure 1).
There are five parts of a BPEL application. The true
BPEL part is an XML file that conforms to the BPEL
standard (BPEL4WS 1.1 and WS-BPEL 2.0). This file
Figure 2:
contains the definition of the activities that make up
the BPEL process. Another part are the services that
get integrated by BPEL; these are defined by standard J2EE or .NET. Active Endpoints provides a complete set
WSDL files. The other three parts are the proprietary of administrative tools and a sophisticated development
BPEL engine that runs the processes, the proprietary environment based on the Eclipse IDE (see Figure 2).
graphic designer that functions as the IDE or the devel- Active Endpoints created the open source ActiveB-
opment environment that allows drag ’n’ drop design PEL Engine to generate interest in the BPEL standard
of processes, and the final part is the administrative and to help educate the community about BPEL.
tools for deploying and monitoring the BPEL process. The open source ActiveBPEL Engine is uses the same
BPEL is considered “programming in the large” be- source code as used in the ActiveBPEL commercial
cause it deals with higher-level constructs such as flow products. The open source version is recommended for
control and looping, processes that are long running design and testing, but not for deployment because it
(for instance, a request for a loan approval might be lacks the system integration, clustering support, and
routed to the accounting department and sit there for security that are included in the commercial versions
days before being approved or denied), fault tolerance and typically needed in enterprise-level BPEL imple-
(it can be set up to start an alarm process if accounting mentations. The open source version does contain
does not respond to the loan request within a week), everything needed to create and run BPEL applica-
and it uses compensation instead of transactions (a tions without these enterprise-level features, includ-
transaction can’t be kept open for the length of time ing the designer and execution engine, management
needed in a long-running process, so, if a stage of a console, debugging, static BPEL analysis, multiple
process fails, it has to be “fixed,” not just rolled back). languages (XPath, XQuery, JavaScript, and custom
languages), persistence, and all the documentation.
Active Endpoints and ActiveBPEL The open source version is released under the GPL and
Active Endpoints has three versions of their BPEL prod- is maintained by Active Endpoints. Active Endpoints
ucts: a standalone open source version, a standalone com- also provides free forum-based support and premium
About the Author mercial version that can run under either .NET or Tomcat, support on a fee-based subscription basis.
Dennis Hayes is a program- and an integrated commercial version that can run under The commercial standalone (paid license and sup-
mer at Georgia Tech in port) version runs on Tomcat or .NET, and adds sup-
Atlanta, Georgia, where he port for WS-Security, WS-Reliable Messaging, advance
writes software for the Adult process filtering and alerts, suspend and retry via both
Cognition Lab in the Psychol- the console and APIs, enhanced process deployment
ogy Department. He has and invocation, and process versioning (currently run-
been involved with the Mono ning processes use the old version, new instances of a
project for over five years. process use the new version, with the old version being
retired after all running processes end).
dennisdotnet@yahoo.com Figure 1:
–continued on page 19

34 June 2007 Volume: 5 Issue: 6 Visit us at www.dotnetdevelopersjournal.com


Visit us at www.dotnetdevelopersjournal.com June 2007 Volume: 5 Issue: 6 35
36
June 2007 Volume: 5 Issue: 6
Your challenge: create rich, dynamic PC or
mobile apps. Defy it: deliver value, not just
data with Visual Studio® and Windows Vista.TM
More tips and tools at defyallchallenges.com

Visit us at www.dotnetdevelopersjournal.com