MSDN Magazine 11-03
MSDN Magazine 11-03
CUTTING EDGE
Processing Health Care Claims with Application Extensibility:
BizTalk Server 2010 MEF vs. IoC
Dino Esposito page 10
Mark Beckner . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
DATA POINTS
Tips and Tricks for Loading Silverlight Server-Side Paging with the Entity
Framework and ASP.NET MVC 3
Locale Resources Julie Lerman page 16
Matthew Delisle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
FORECAST: CLOUDY
Writing a Debugging Tools for Windows Extension Cloud Services Mashup
Joseph Fultz page 22
Andrew Richards . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
MOBILE MATTERS
Building Data-Centric Web Apps with Windows Phone Navigation:
The Basics
ASP.NET MVC and Ext JS Yochay Kiriaty &
Juan Carlos Olamendy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70 Jaime Rodriguez page 82
UI FRONTIERS
Touch Gestures on Windows Phone
Charles Petzold page 92
............................................................................................
Using Quince™, you and your team can
collaborate on the user interface using
wireframes, designs and examples.
.......................................................................
Then use NetAdvantage® UI controls,
like the map control used here, to bring
the application to life quickly & easily.
...
MSDN Magazine (ISSN 1528-4859) is published monthly by 1105 Media, Inc., 9201 Oakdale Avenue,
Ste. 101, Chatsworth, CA 91311. Periodicals postage paid at Chatsworth, CA 91311-9998, and at
additional mailing offices. Annual subscription rates payable in US funds are: U.S. $35.00, International
$60.00. Annual digital subscription rates payable in U.S. funds are: U.S. $25.00, International $25.00.
Single copies/back issues: U.S. $10, all others $12. Send orders with payment to: MSDN Magazine,
P.O. Box 3167, Carol Stream, IL 60132, email MSDNmag@1105service.com or call (847) 763-9560.
POSTMASTER: Send address changes to MSDN Magazine, P.O. Box 2166, Skokie, IL 60076. Canada
Publications Mail Agreement No: 40612608. Return Undeliverable Canadian Addresses to Circulation
Dept. or XPO Returns: P.O. Box 201, Richmond Hill, ON L4B 4R5, Canada.
Printed in the U.S.A. Reproductions in whole or part prohibited except by written permission. Mail requests
to “Permissions Editor,” c/o MSDN Magazine, 16261 Laguna Canyon Road, Ste. 130, Irvine, CA 92618.
Legal Disclaimer: The information in this magazine has not undergone any formal testing by 1105 Media,
Inc. and is distributed without any warranty expressed or implied. Implementation or use of any information
contained herein is the reader’s sole responsibility. While the information has been reviewed for accuracy,
there is no guarantee that the same or similar results may be achieved in all environments. Technical
inaccuracies may result from printing errors and/or new developments in the industry.
Media Kits: Direct your Media Kit requests to Matt Morollo, VP Publishing, 508-532-1418 (phone),
508-875-6622 (fax), mmorollo@1105media.com
Reprints: For single article reprints (in minimum quantities of 250-500), e-prints, plaques and posters contact:
PARS International, Phone: 212-221-9595, E-mail: 1105reprints@parsintl.com, www.magreprints.com/
QuickQuote.asp
List Rental: This publication’s subscriber list, as well as other lists from 1105 Media, Inc., is available
for rental. For more information, please contact our list manager, Merit Direct. Phone: 914-368-1000;
E-mail: 1105media@meritdirect.com; Web: www.meritdirect.com/1105
866-719-1528 programmersparadise.com
Prices subject to change. Not responsible for typographical errors.
Last month, I talked about some of the best ways to get published Now, a few words about how to get your article rejected after it’s
in MSDN Magazine. That naturally led me to think of some equally been accepted for publication. The first, best (worst?) thing you can
good ways to not get published in the magazine. If February was do is not communicate with the staff, beginning with me. It’s hap-
the list of dos, this is the list of don’ts. Follow these rules (or is that pened numerous times that an author is late with an article. Hey, stuff
“don’t follow these rules”—I get confused with negatives) to give happens, and delays can be caused by any number of circumstances.
your query the best shot at not getting a positive response from What drives me to distraction is when an author doesn’t inform me
me and the team. that an article or requested bit of information will be late. I can almost
The best way to ensure your query doesn’t get accepted, or even always work around delays; to do that, however, I need to hear from
considered, is to put it in the wrong format. We’ve written a guide to you. Even if you come to the conclusion that you won’t be able to turn
the proper formatting of queries, which you can find at bit.ly/eZcovQ. in an article at all (it happens sometimes), let me know so I can make
One of the critical pieces of information in the document is the title alternative arrangements. If I don’t know, however, it throws a shiny
of your query. It should state “MSDN Article Query” in the subject steel monkey wrench right into the middle of our processes, and
line—and nothing else. Please don’t get cute with the title; clever makes me (and my staff ) miserable. Please don’t make us miserable.
subject lines don’t thrill me. Like you, I get tons of e-mail each day, Other reasons your submitted article can be rejected:
and I need to quickly separate the wheat from the chaff. If you’ve • Plagiarism. You can’t copy and paste from published docu-
got the right title, I’ll look over the query; if not, it’s ye olde Delete ments. At all. Not nowhere, not nohow. “That’s obvious!” you
key for your e-mail. say. You’d be surprised at how un-obvious it is to some writers.
Another way to hurt your chances: Make your query novella • Sloppy writing. See my section about the query. You may
length. My eyes glaze over when I open an article query and notice not be the Shakespeare of dev authors, but strive to turn in
that it will take quite a lot of scrolling to get through it all. Brevity is your best work. That means after you write the article, get
key here—short, sweet and clear. If you can’t do this in your query, away from it for a day and go back and edit it. Then do it
I’ll have serious doubts about whether you can do it in an article. again. If information is unclear or incomplete, fix it. Don’t
That brings up another crucial point: Your query, if I haven’t expect us to do it all for you. If we do that, and still publish
worked with you before, is your initial writing audition. Writing your article anyway because we love the topic, be assured
for MSDN Magazine isn’t like writing a blog entry—you don’t need you won’t get assigned a second article.
to have been previously published, but you do need to demonstrate • Failure to follow writer’s guidelines. All authors get a copy of
at least basic writing chops. If your query is full of misspellings, our writing guidelines. I suspect some of them barely glance
sloppy grammar and missing information, you’ll get turned down, at the document. Don’t let this be you. There are specific
guaranteed. After all, if I can’t trust you to write a proper query, I’m rules that need to be followed. Learn them. Love them.
surely not going to trust you to write an entire article. One of the best parts of my job is working with authors. I try to
One last item about queries: Please don’t make your pitch in make it a relaxed, enjoyable process. You can do your part to help me
an attached Word document. I’m not keen on downloading and by avoiding these don’ts. Send your
opening attachments just to read a query. Include the query in the (properly formatted!) article ideas to
body of the e-mail—please! me at mmeditor@microsoft.com.
Visit us at msdn.microsoft.com/magazine. Questions, comments or suggestions for MSDN Magazine? Send them to the editor: mmeditor@microsoft.com.
4 msdn magazine
Untitled-1 1 2/9/11 10:43 AM
TOOLBOX TERRENCE DORSEY
WCF Soap Services (bit.ly/icbLnR) that will help you understand the
strengths of each approach.
How about putting a bunch of these technologies together into
one interesting sample? Shawn Wildermuth, in his article “WCF Data
Services and jQuery” (bit.ly/hVCMWd), builds a Web app that uses
jQuery to retrieve data in JSON format, exposes the data as entities
via Entity Framework, and then uses WCF Data Services to expose
the entities via REST. I think we have a “Buzzword Bingo” winner here.
A highly rated tool for making sense of your data sources is the
Open Data Protocol Visualizer extension for Visual Studio 2010
(bit.ly/dWt19X), which displays the types and relationships provided by
WCF Data Services in simplified diagram form. Read Audrey Petit’s
“Open Data Protocol Visualizer Extension for Visual Studio
2010” blog post (bit.ly/hKSKRx) to learn how it works.
NHibernate
NHibernate (nhforge.org) is an open source O/RM framework for
development with the .NET Framework. Like the Entity Framework,
LINQPad NHibernate lets you map databases to entities and allows simplified
programmatic access to the data.
WCF Data Services and OData Because it’s a community-driven effort, there are lots of useful
WCF Data Services—formerly known as ADO.NET Data Services—lets resources available for learning and using NHibernate in your
you share, consume and update data via HTTP using the OData projects. One great way is to jump in and start coding. Gabriel
protocol (odata.org). Like the Entity Framework, WCF Data Services Schenker’s “Your Very First NHibernate Application” series of
uses an Entity Data Model (EDM) to bridge between data source and articles on dotnetslackers.com (direct link: bit.ly/exFATb) is one such
program entities. You can read more about WCF Data Services on tutorial. Another is Mitch Fincher’s “Learning with Code Samples”
MSDN at bit.ly/hnuvwv. for NHibernate (bit.ly/e91Nzv).
To get you started, Shayne Burgess walks you through the basics Would you rather see the movie? Well then, check out the
of using OData and Data Services in the article, “Building Rich Summer of NHibernate (summerofnhibernate.com) screencast series,
Internet Apps with the Open Data Protocol,” in the June 2010 which walks you step-by-step from getting set up to writing your first
issue of MSDN Magazine (bit.ly/gPZGDc). queries to advanced topics like modeling inheritance and managing
Not sure which WCF services to use for your data-centric app? session state. There’s a lot to watch, so get your popcorn ready and
Tony Sneed wrote an in-depth appraisal of WCF Data Services vs. settle in for a few evenings of learning.
Zentity
Many business and social apps run
on data, but researchers are
increasingly creating and sorting
through huge data sources from
clinical studies, experimental results
and even celestial observations. In
response, Microsoft Research
released Zentity 2.0 (bit.ly/fiFPb3),
a data library framework that can
be used for storing, accessing and
analyzing data using SQL Server
2008. The new version of Zentity
leverages the .NET Framework 4
with support for WCF Data
Services and OData, LINQ, Entity
Framework, Windows PowerShell
and more.
can manage the lifetime of created instances and offer caching public class FindTheNumberFormBase : Form, IFindTheNumberApi {
and pooling capabilities. Third, most IoC frameworks support in- ...
}
terception and offer to create dynamic proxies around instances
10 msdn magazine
Untitled-5 1 2/2/11 1:19 PM
answer is no, then the best approach is using an IoC framework Figure 2 The Site Object for Plug-Ins
unless you have basic needs that the MEF can address as well. All public class FindTheNumberSite {
things being equal, the MEF is preferable to an IoC framework private readonly FindTheNumberFormBase _mainForm;
because it’s built right into the .NET Framework and you don’t need public FindTheNumberSite(FindTheNumberFormBase form) {
to take any additional dependencies. _mainForm = form;
}
The MEF and Extensible Applications public T FindElement<T>(String name) where T:class { ... }
public void AddElement(Control element) { ... }
While the MEF helps in the building of an extensible application,
the most delicate part of the job is designing the application for public Int32 Height {
get { return _mainForm.Height; }
extensibility. This is design and has little to do with the MEF, IoC set { _mainForm.Height = value; }
or other technologies. In particular, you must figure out which }
parts of your application you intend to make available to plug-ins. public Int32 Width { ... }
A plug-in is often a visual element and needs to interact with the public Int32 NumberOfAttempts { ... }
public Boolean IsUserPlaying { ... }
UI of the main application, add or extend menus, create panes, dis- public Int32 LowerBound { ... }
play dialog boxes, or even add or resize the main windows. Depend- public Int32 UpperBound { ... }
public void SetNumber(Int32 number) { ... }
ing on how you envision the plug-ins of your specific application, }
the amount of information to share with plug-ins may consist of
just business data (essentially a segment of the application’s current submitted for a new try. Finally, ShowUserInterface is invoked
state) or reference to visual elements such as containers, menus, when the plug-in must show up in the window. In this case, a site
toolbars and even specific controls. You group this information object is passed, as defined in Figure 2.
in a data structure and pass it down to the plug-in at initialization The site object represents the point of contact between the
time. Based on that information, the plug-in should be able to plug-in and the host application. The plug-in must gain some
adjust its own UI and implement its own additional custom logic. visibility of the host state and must even be able to modify the
Next comes the interface for the plug-ins. The interface depends host UI, but it never gains knowledge of the host’s internal details.
on the injection points you’ve identified in your main application. By That’s why you might want to create an intermediate site object
“injection point” I mean the places in the application’s code from which (part of your SDK assembly) that plug-in projects must reference.
you’d invoke plug-ins to give them a chance to kick in and operate. I omitted for brevity the implementation of most methods in
As an example of an injection point, consider Windows Explorer. Figure 2, but the constructor of the site object receives a refer-
As you may know, Windows Explorer allows you to extend its UI ence to the application’s main window, and using helper methods
via shell extensions. These plug-ins are invoked at very specific in Figure 1 (exposed by the main window object) it can read and
moments—for example, when the user right-clicks to display the write the application’s state and visual elements. For example, the
properties of a selected file. As the application’s architect, it’s your Height member shows how the plug-in may read and write the
responsibility to identify these injection points and what data you height of the host window.
intend to pass to registered plug-ins at that point. In particular, the FindElement method allows the plug-in (in the
Once every design aspect has been cleared up, you can look sample application) to retrieve a particular visual element in the
around for frameworks that can simplify the task of building a form. It’s assumed that you unveil as part of your SDK some tech-
plug-in-based application. nical details of how to access certain containers such as toolbars,
menus and the like. In such a simple application, it’s assumed
A Sample Plug-In-Based Application that you document the ID of the physical controls. Here’s the
Even a simple application such as “Find the number” can be made implementation of FindElement:
richer and functionally appealing using plug-ins.
You might want to create a separate project to define the SDK Figure 3 Initializing the MEF
of your application. It will be a class library where you define all private void InitializeMef() {
classes and interfaces required to implement plug-ins. Figure 1 try {
_pluginCatalog = new DirectoryCatalog(@"\My App\Plugins");
shows an example. var filteredCatalog = new FilteredCatalog(_pluginCatalog,
All plug-ins are required to implement the IFindTheNumber- cpd => cpd.Metadata.ContainsKey("Level") &&
!cpd.Metadata["Level"].Equals("Basic"));
Plugin interface. The main application form will inherit from the
specified form class, which defines a list of public helper members // Create the CompositionContainer with the parts in the catalog
_container = new CompositionContainer(filteredCatalog);
useful to pass information down to plug-ins. _container.ComposeParts(this);
As you may guess from IFindTheNumberPlugin, registered }
catch (CompositionException compositionException) {
plug-ins are invoked when the application displays its UI, when ...
the user makes a new attempt to guess the number, and when the }
catch (DirectoryNotFoundException directoryException) {
game is started and stopped. GameStarted and GameStopped are ...
just notification methods and don’t need any input. NumberEntered }
}
is a notification that brings in the number the user just typed and
Writing a Sample Plug-In D INO E SPOSITO is the author of “Programming Microsoft ASP.NET MVC”
A plug-in is just a class that implements your app’s extensibility (Microsoft Press, 2010) and coauthored “Microsoft .NET: Architecting Applications
interface. An interesting plug-in for the application is one that for the Enterprise” (Microsoft Press, 2008). Based in Italy, Esposito is a frequent
shows the number of attempts the user made so far. The number speaker at industry events worldwide. You can join his blog at weblogs.asp.net/despos.
of attempts is being tracked by the business logic of the applica-
tion, and it’s exposed to plug-ins via the site object. All a plug-in THANKS to the following technical expert for reviewing this article: Glenn Block
14 msdn magazine Cutting Edge
Untitled-5 1 2/2/11 1:20 PM
DATA POINTS JULIE LERMAN
Silverlight, .NET,
Windows Phone,
WPF, WCF, WF,
C API, C++ Class
Lib, COM & more!
Free 60 Day Evaluation! DICOM Medical Form Recognition & Processing Vector
www.leadtools.com/msdn
(800) 637-1840
J ULIE L ERMAN is a Microsoft MVP, .NET mentor and consultant who lives
in the hills of Vermont. You can find her presenting on data access and other
Microsoft .NET topics at user groups and conferences around the world. Lerman
blogs at thedatafarm.com/blog and is the author of the highly acclaimed book,
“Programming Entity Framework” (O’Reilly Media, 2009). You can follow her
at Twitter.com/julielerman.
Figure 5 A Single Page of Customers with Navigation Links to THANKS to the following technical expert for reviewing this article:
Go to Previous or Next Page of Customers Vishal Joshi
Up until now, I’ve spent time on solutions using Microsoft Windows Figure 1 Cloud Services and Their Functionalities
Azure or SQL Azure to augment solution architecture. This month Service Functionality
I’m taking a look at how to combine multiple cloud services into a
Windows Azure Host my site and serve pages
single app. My example will combine Windows Azure, Windows
AppFabric Manage and negotiate authentication between my site
Azure AppFabric Access Control, Bing Maps and Facebook to
Access Control and Facebook
provide an example of composing cloud services.
Facebook Authenticate users and provide social network services
For those who are a little put off when thinking about federated
Bing Maps Visualize friends’ hometowns
identity or the real-world value of the social network, I’d like to
introduce Marcelus. He’s a friend of mine who owns a residential
and commercial cleaning company. Similar to my father in his This summary page is important, as I’ll need to use information
business and personal dealings, he knows someone to do or get just from it in my configuration of Facebook as an Identity Provider in
about anything you want or need, usually in some form of barter. ACS. In particular, I’ll need the Application ID and the Application
Some might recognize this as the infamous good ol’ boys’ network, secret as can be seen in the configuration information from ACS
but I look at Marcelus and I see a living, breathing example of the shown in Figure 3.
Windows Azure AppFabric Access Control service (or ACS for Note that I’ve added friends_hometown to the Application
short) combined with a powerful social network. In real life I can permissions text box. I’ll need that address to map it, and without
leverage Marcelus and others like him to help me. specifying it here I wouldn’t get it back by default. If I wanted some
However, in the virtual world, when I use a number of cloud other data to be returned about the user by the Graph API calls, I’d
services they often need to know who I am before they allow me to
access their functionalities. Because I can’t really program Marcelus
to serve Web pages, I’m going to use the cloud services in Figure 1
to provide some functionality.
The scenario is that navigation to my site’s homepage will be
authenticated by Facebook and the claims will be passed back to
my site. The site will then pull that user’s friends from Facebook
and subsequently fetch information for a selected friend. If the
selected friend has a hometown specified, the user may click on
the hometown name and the Bing Map will show it.
22 msdn magazine
www.devart.com
Figure 3 ACS Facebook Identity Provider Configuration Using this information, the
wizard will add the config section
need to look it up at the Facebook Developers site (bit.ly/c8UoAA) and <microsoft.identityModel/> to the site configuration. Once this
include the item in the Application permissions list. is done, add <httpRuntime requestValidationMode=“2.0” />
Something worth mentioning when working with ACS: You spec- underneath the <system.web/> element. Providing that I specified
ify the Relying Parties that will use each Identity Provider. If my site localhost as a relying party, I should be able to run the application,
exists at jofultz.cloudapp.net, it will be specified as a relying party on and upon startup be presented with an ACS-hosted login page that
the Identity Provider configuration. This is also true for my localhost. will present Facebook—or Windows Live or Google, if so config-
So, in case I don’t want to push to the cloud to test it, I’ll need to con- ured. The microsoft.identityModel element is dependent upon
figure a localhost relying party and select it, as illustrated in Figure 4. existence of the Microsoft.Identity assembly, so you have to be
sure to set that DLL reference in the site to Copy Always. If it isn’t,
}
I create an FBHelper class where I’ll create the methods to
Not wanting to be left out of the inner circle of those who use access the Facebook information that I desire. To start, I create
such a fantastic app, I quickly click Allow, after which Facebook, a method to help make all of the needed requests. I’ll make each
ACS and my app exchange information
(via browser redirects) and I’m finally
redirected to my application. At this
point I’ve simply got an empty page,
but it does know who I am and I have
a “Welcome Joseph Fultz” message at
the top right of the page.
SIGN UP
FOR THE SAFARI
BOOKS ONLINE
OPEN HOUSE
Find all the latest and
most relevant resources
for Microsoft Developers
and IT developers at
Safari Books Online.
UNLIMITED ACCESS. Sign up today for the Safari Books Online Open House and get your team or
workgroup access to the world’s most popular, fully searchable digital library.
UNLIMITED VALUE.
See why more than 15 million business and IT professionals, developers
and web designers from corporations, government agencies and academic
institutions access Safari Books Online for research, problem solving, just-in-
time learning, professional development and certification training.
New! PDF Integration into Silverlight Applications ■ Develop with .NET, Java or C++
■ Server-side PDF component based on the robust Amyuni PDF ■ Unrestricted development and
Creator ActiveX or .NET components flexible quantities
■ ■ Fully supported in North America
Client-side C# Silverlight 3 control provided with source-code
■ Optimization of PDF documents prior to converting them into XAML
■ Conversion of PDF edit-boxes into Silverlight TextBox objects
■ Support for other document formats such as TIFF and XPS Learn more at www.devtouchpro.com
www.amyuni.com
All trademarks are property of their respective owners. © 1999-2010 AMYUNI Technologies. All rights reserved.
Cloud-Based
Collaboration with
SharePoint Online
Chris Mayo
With the release of Office 365, Microsoft will present ment is similar to and different from SharePoint 2010 development
the next version of Microsoft Online Services, a cloud-based col- by building solutions that run in SharePoint Online.
laboration and communication service based on SharePoint 2010, With the next release of SharePoint Online, SharePoint developers
Exchange 2010 and Lync Server 2010. Office 365, currently in beta, will be able to develop collaboration solutions using the same skills
will provide SharePoint, Exchange and Lync as a subscription-based and tools they use in developing for SharePoint 2010, including
Software as a Service (SaaS) offering, hosted in cloud datacenters Visual Studio 2010, SharePoint Designer 2010, C# or Visual Basic
managed by Microsoft. and the SharePoint APIs and SDKs. There are many similarities
SharePoint Online—the cloud-based version of SharePoint 2010— between developing for SharePoint on-premises and in the cloud,
will provide users with many of the same features of SharePoint but there are also significant differences that will impact how you
2010, but without the need to manage the hardware or software build solutions.
required for a scalable and secure collaboration solution. In this Understanding these differences will help you understand what
article, I’ll provide an overview of how SharePoint Online develop- solutions can be created to run in SharePoint Online and how to
develop those solutions.
This article is based on prerelease versions of Office 365 and
SharePoint Online. All information is subject to change. SharePoint Online Customization Similarities
In SharePoint 2010 development, you have the ability to customize
This article discusses: SharePoint using the browser and SharePoint Designer 2010 and
• SharePoint Online customization similarities and differences by building solutions using Visual Studio 2010. With SharePoint
• Developing for SharePoint Online with sandboxed solutions Online, customization with the browser and SharePoint Designer
• Creating client-side solutions with Silverlight 2010 is largely the same as SharePoint 2010 (given the feature dif-
ferences mentioned in the next section). Developing SharePoint
Technologies discussed:
Online solutions using Visual Studio 2010 is also largely the same.
SharePoint Online, SharePoint 2010 Development is done in Visual Studio 2010 against a local instance of
Code download available at: SharePoint 2010 (either running locally in Windows 7 or Windows
code.msdn.microsoft.com/mag201102SPOnline
Server 2008 R2 or in a virtual machine, or VM), leveraging the
integrated debugging experience for iterative development. When
32 msdn magazine
where multiple tenancies run on a shared datacenter infrastruc-
ture, so it make sense that solutions with Farm scope (where a
feature is activated for the entire farm) aren’t supported. Likewise,
in SharePoint Online, the highest level of access to your SharePoint
tenancy is at the site-collection level, so WebApplication-scoped
features (where a feature runs in every Web site in a Web application)
aren’t supported either.
Second, only partial-trust solutions are supported in SharePoint
Online. Full-trust solutions, where your solution would have access
beyond the site-collection level or could be granted permission to
run with admin-level privileges on the farm, also aren’t supported.
Finally, although SharePoint Online is based on SharePoint 2010,
it doesn’t have 100 percent feature parity with its on-premises coun-
terpart. For a complete feature-by-feature comparison between
SharePoint 2010 and SharePoint Online, refer to the Microsoft
SharePoint Online Beta Service Description, available from the Office
Figure 1 Specify the Site and Trust Level for PurchasingMgr 365 Beta Service Descriptions page at bit.ly/bBckol.
The feature-by-feature list shows that a majority of SharePoint
development is complete, the solution is uploaded to SharePoint customization features are supported. The lack of support for Busi-
Online using the same Solution Gallery provided in SharePoint 2010. ness Connectivity Services (BCS), External Lists and the ability to
call Web services outside SharePoint Online (which isn’t supported
SharePoint Online Customization Key Differences in partial-trust solutions) will have a significant impact on building
Although SharePoint Online is based on SharePoint 2010, there solutions that run in SharePoint Online. BCS support is planned
are some key differences to keep in mind as you develop solutions for a future release, however.
that will run in the former. First, SharePoint Online only supports With these similarities and differences in mind, let’s look at some
Site- and Web-scoped solutions. It runs in a multi-tenant cloud, examples of the types of solutions you can build to run in SharePoint
in SharePoint Online named Purchasing using the Team Site <TextBox Name="Title" Grid.Column="1" Grid.Row="0" Margin="3"/>
template. Back in Visual Studio 2010, I’ll package the solution by <TextBox Name="Description" Grid.Column="1" Grid.Row="1" Margin="3"/>
<TextBox Name="Price" Grid.Column="1" Grid.Row="2" Margin="3"/>
right-clicking on the PurchasingMgr project in the Solution Explorer
and selecting Package. To deploy the solution to SharePoint Online, <Button Content="Add" Grid.Column="1" Grid.Row="3" Margin="3"
Name="addNonStanPurchaseReq" HorizontalAlignment="Right"
I’ll just need to upload it to the Solution Gallery and activate the Height="25" Width="100" Click="addNonStanPurchaseReq_Click" />
site features (I’ll need site collection administrator privileges to </Grid>
</UserControl>
do so). To do this, I’ll log in to SharePoint Online and navigate to
36 msdn magazine SharePoint Online
Untitled-8 1 2/8/11 1:34 PM
Creating Client-Side Solutions
with Silverlight
The client OM, also introduced with SharePoint
2010, provides an object-oriented, client-side API
for SharePoint clients built using the Microsoft
.NET Framework, Silverlight and ECMAScript (in-
cluding JavaScript and JScript) that run on remote
computers (including the browser for Silverlight
and ECMAScript). The API is consistent with the
Microsoft.SharePoint server-side namespace, so
it’s easy to learn. The API is also consistent across
the supported client types, so it’s easy to apply that
knowledge across different client solutions. The
client OM API is supported in SharePoint Online
and is a valuable tool for cloud development.
For example, I can use the client OM to create
a Silverlight 4 application to add items to my list
and host the application in a sandboxed Web Part.
Figure 9 MainPage.xaml in Designer To do this, I’ll open Visual Studio 2010, select File |
New Project and in the New Project dialog select
Purchasing Manager - Content Types and Lists feature and select Empty SharePoint Project. I’ll name the project PurchasingMgrWP
Activate. At this point you should see the Non-Standard Business and click OK. Again, I’ll create the solution as a sandboxed solu-
Purchase Requests lists in your SharePoint Online site. tion and point it at my on-premises Purchasing site. To create the
The Purchasing Manager is just one example of what you can ac- Silverlight 4 application, I’ll right-click on the PurchasingMgrWP
complish in SharePoint Online with sandboxed solutions. Keep in solution, select Silverlight under Installed Templates, select
mind the limitations in sandboxed solutions and in the SharePoint Silverlight Application and name the solution NonStandBus-
Online supported features, and you can create solutions that will PurchaseReqsSLOM. In the New Silverlight Application dialog,
run in SharePoint 2010 or SharePoint Online. I’ll uncheck “Host the Silverlight application in a new Web Site”
Figure 10 addNonStanPurchaseReq_Click
using System; "Non-Standard Business Purchase Requests");
using System.Collections.Generic;
using System.Linq; ListItem newListItem =
using System.Net; nonStandBusPurList.AddItem(new ListItemCreationInformation());
using System.Windows; newListItem["Title"] = Title.Text;
using System.Windows.Controls; newListItem["RequestDescription"] = Description.Text;
using System.Windows.Documents; newListItem["Price"] = Price.Text;
using System.Windows.Input;
using System.Windows.Media; newListItem.Update();
using System.Windows.Media.Animation;
using System.Windows.Shapes; clientContext.Load(nonStandBusPurList, list => list.Title);
InitializeComponent();
} private void onQueryFailed(object sender,
ClientRequestFailedEventArgs args)
private void addNonStanPurchaseReq_Click(object sender, RoutedEventArgs e) {
{ Dispatcher.BeginInvoke(() =>
ClientContext clientContext = new ClientContext(webUrl); {
MessageBox.Show("Request failed. " + args.Message + "\n" +
Web webSite = clientContext.Web; args.StackTrace);
ListCollection webLists = webSite.Lists; });
}
List nonStandBusPurList = }
clientContext.Web.Lists.GetByTitle( }
} this.Controls.Add(slhc);
} }
} }
} }
Copyright 1996-2010 Infragistics, Inc. All rights reserved. Infragistics, the Infragistics logo and NetAdvantage are registered trademarks of Infragistics, Inc.
Motion Framework is a trademark of Infragistics, Inc.
Processing Health
Care Claims with
BizTalk Server 2010
Mark Beckner
BizTalk Server 2010 introduces an entirely re-architected • Configuring ports to enable reception or delivery of docu-
platform for managing the exchange of Electronic Data Interchange ments, whether over FTP, AS2 or another protocol.
(EDI) documents between trading partners. If you’ve worked with For purposes of illustration, we’ll look at the exchange of doc-
earlier editions of the platform, you may have encountered some uments between a hospital and a claims-processing unit. The
headaches with setting up document exchange between various documents exchanged between parties will be Health Insur-
parties. With the latest release, you have complete control over ance Portability and Accountability Act (HIPAA)-compliant 837
the organization and configuration of document settings related Professional and Institutional files.
to any interchange between parties.
BizTalk Server 2010 also provides a much-improved experience Working with Schemas
when developing maps. In most EDI solutions, you’ll be working with two basic types of
To illustrate these new features, I’m going to walk you through schema: the EDI schemas that represent the flat files exchanged with
the steps required for building out an EDI solution. Every EDI trading partners, and the internal schemas that represent document
solution developed in BizTalk Server 2010 follows a basic pattern: types needed for processing the data within the EDI document.
• Adding and modifying base EDI schemas. In my example, the solution exchanges the 837 documents with
• Creating maps between the EDI document and internal/ external parties, but uses a different document format for internal
external messaging. processing. The internal schema represents an ECSIF flat file: a
• Implementing orchestrations to handle workflow associated common format for claims processors. The 837 schemas that ship
with processing the EDI documents. with BizTalk and can be added to a Visual Studio project, but the
• Configuring trading partner settings, including parties, internal schemas (such as an ECSIF) must be built by hand.
business profiles, agreements and acknowledgments. BizTalk Server 2010 ships with thousands of existing schemas
that define a majority of the EDI documents in use today. To access
This article discusses: the schemas, run the MicrosoftEdiXSDTemplates.exe executable
found in the $\Program Files\Microsoft BizTalk Server 2010\XSD_
• EDI schemas
Schema\EDI directory. For the purposes of this example, I’ll use
• Developing EDI maps
the 837 Professional and Institutional HIPAA-compliant schemas
• Trading partner configurations found in the HIPAA\00501 folder. Adding the XSD file to a Visual
• Ports and document delivery Studio project allows it to be referenced and used by other BizTalk
Technologies discussed: components—most importantly, by maps.
BizTalk Server 2010
Figure 1 shows the 837 Professional 5010 schema within Visual
Studio 2010. Notice the number of nodes on this schema: the 837 is
44 msdn magazine
one of the most complex EDI documents, shelling out to an external XSLT stylesheet is
and can be extremely tricky to work with. in order (which bypasses the BizTalk mapper
It contains hundreds of nodes that are vir- altogether). EDI maps can become compli-
tually identical, representing subscriber cated and require ingenuity and planning to
and patient information. end up with the needed solution.
Figure 2 shows the internal schema rep- To illustrate the use of inline C#, let’s
resenting the ECSIF format. This schema look at a common function of mapping
was generated using the Flat File Schema an outbound 837 Professional or Insti-
Wizard. The wizard can be pointed to a tutional file: the mapping of hierarchical
valid flat file instance to create an XSD. (HL) segments. The HL segments require
A number of the fields in the FileHeader incremental values for each record in the
node have been promoted in this schema. file, and denote parent/child relationships.
Promoted fields allow for improved filter- There really is no traditional functoid
ing and mapping options. combination that will allow these values
Once the schemas have been defined to be set properly. There is, however, a
and added to the Visual Studio project, simple inline C# approach that allows for
you can begin building out the maps. In the correct values. This approach requires
this case, I’ll look at several scenarios that two scripting functoids: one that stores a
are useful in mapping an 837 document. Figure 1 The 837 Professional 5010 Schema global variable and maps HL01, while the
second maps HL02 (which is dependent
Developing Maps on the value of HL01).
The mapping interface in BizTalk Server 2010 has The HL01 functoid script looks like this:
been extensively revised and introduces a variety of int intHL01;
public int getHL01() {
new capabilities. These capabilities include zoom- intHL01++;
ing, automatic node matching and search capabili- return intHL01;
}
ties. One of the most noticeable enhancements is
the ability to click on a line or functoid and have all Here’s the code for the HL02 script:
public int getHL02() {
other mappings fade into the background. return intHL01 -1;
As any EDI map developer will know, some maps }
get extremely complex, with multiple tabs and Figure 4 shows the functoids placed in the map.
dozens (or even hundreds) of functoids. Finding Another situation that frequently arises in
out what data in the source schema maps to what mapping EDI documents is the need to use inline
data in the target schema and what functoids are Figure 2 The Target ECSIF XSLT. This is one of the most important skills to
being used to do this mapping can be difficult to Schema Format incorporate into BizTalk mapping, and is some-
visualize. By clicking on any of the lines or func- thing you should acquaint yourself with. It allows
toids used, all related mappings will be highlighted. for many options around looping and node creation that simply
An example of a complex map with a specific set of mapping aren’t available using standard functoid combinations.
logic highlighted is shown in Figure 3 . This brings up a point One illustration of using Inline XSLT in a map is shown in Figure
of BizTalk map development that’s often overlooked: there are 5. This code demonstrates how to use the Inline XSLT Call Template
times to use the map interface, and there are times not to use it. functionality to pass in a parameter from the source document
Not all mapping that’s done in BizTalk is best suited for standard (Name) and create a node in the target 837 document.
mapping—sometimes using alternative approaches is in order. When developing a BizTalk map, always think about the long-
Alternatives include inline scripting and external components, term maintainability of the map. Is this something that you’ll be
including XSLT and Microsoft .NET Framework components. able to easily update? Is this something that someone else can work
BizTalk map development generally consists of a combination of with in the future? Good coding practice should not be forgotten
standard functoids and inline XSLT and C#. There are even times when when working with BizTalk maps, and some amount of architecture
Orchestrations
The use of orchestrations in EDI solutions is not a requirement. Often,
documents simply need to be mapped from one format to another
and delivered, without the need for the inclusion of workflow.
Figure 4 Mapping HL Segment on Outbound 837 In some cases, however, a document may need to have several
steps of processing done to it before it’s ready to be
delivered. To illustrate this, I’ll set up an orchestration to
map and archive messages to a table in SQL Server. The
orchestration will be configured with a filter to ensure
only documents of a certain type are processed by it.
location is straightforward.
settings and acknowledgments, simply save the agreement settings as
a template and use them as the starting point for future agreements.
Port Configurations and Document Delivery To understand how ports process EDI documents, let’s look
The actual delivery of documents to or from BizTalk to external at sending an acknowledgment. As you saw earlier, acknowledg-
trading partners is done through the configuration of ports. The ments are configured on the agreements of a BizTalk party. When
port defines the type of delivery mechanism (FTP, file and so a document arrives, BizTalk can automatically generate a 997
on) and contains the BizTalk pipeline that transforms the XML acknowledgment. What happens is that BizTalk creates the 997
XML and drops it on the BizTalk message box, but it
doesn’t actually route the message anywhere. A send
port must be set up and configured to convert the
XML to a flat file, add the envelope and deliver it to the
appropriate destination.
Setting up the send port to deliver an acknowledg-
ment requires three basic steps:
1. The definition of the send port and delivery protocol
2. The inclusion of the EdiSend pipeline (or custom
Figure 11 Configuring Acknowledgements on an Agreement pipeline with EDI pipeline components)
3. The configuration of filters to listen for appro-
priate acknowledgments
Configuring the send port to deliver documents to
a specific location is straightforward. Figure 12 shows
a Send Port configured with the EdiSend pipeline. The
send port will write files out to a file directory with the
full EDI envelope and formatting in place.
Setting the filter on the send port is also easy to do.
It simply requires specifying that it should only pick
up acknowledgments generated by the system for this
trading partner (as opposed to incoming 997s from the
partner). Figure 13 shows a fully configured set of filters.
ENTERPRISE
TELNET WEB UDP
UI SSH
SSL EMULATION TCP
PowerSNMP for ActiveX and .NET PowerTCP for ActiveX and .NET
Create custom Manager, Agent and Trap applications with a set Add high performance Internet connectivity to your ActiveX, .NET
of native ActiveX, .NET and Compact Framework components. and Compact Framework projects. Reduce integration costs with
SNMPv1, SNMPv2, SNMPv3 (authentication/encryption) and detailed documentation, hundreds of samples and an expert
ASN.1 standards supported. in-house support staff.
Silverlight is a great framework for creating rich Internet I’ll present another localization solution that has some benefits over
applications (RIAs), but it doesn’t yet provide the robust support for the standard process. Finally, I’ll round off the solution with a discus-
localization that you enjoy in other components of the Microsoft sion of the back-end components needed to complete the solution.
.NET Framework. Silverlight does have .resx files, a simple Resource-
Manager class and an element in the project file. But after that you’re The Standard Localization Process
on your own. There are no custom markup extensions, and no I’ll start by building a Silverlight application that uses the localiza-
support for the DynamicResource class. tion process outlined by Microsoft. A detailed description of the
In this article I’ll show you how to remedy all of these issues. I’ll process is available at msdn.microsoft.com/library/cc838238(VS.95).
present a solution that will allow a developer to load resource sets The UI contains a TextBlock and an Image, as shown in Figure 1.
at run time, use any format for storing resources, change resources The localization process described by Microsoft uses .resx files
without recompiling and demonstrate lazy loading of resources. to store the resource data. The .resx files are embedded in the main
This article is divided into three parts. First, I’ll develop a simple assembly or a satellite assembly and loaded only once, at application
application using the localization process detailed by Microsoft. Next, startup. You can build applications targeted at certain languages by
modifying the SupportedCultures element in the project file. This
sample application will be localized for two languages, English
This article discusses:
and French. After adding the two resource files and two images
• Locale resource basics representing flags, the project structure looks like Figure 2.
• A smart resource manager I changed the build action for the images to content so I can ref-
• Using a WCF service erence the images using a less verbose syntax. I’ll add two entries to
• Loading the neutral locale each file. The TextBlock is referenced via a property called Welcome,
and the Image control is referenced via a property called FlagImage.
Technologies discussed:
When resource files are created in a Silverlight app, the default
Silverlight modifier for the generated resource class is internal. Unfortunately,
Code download available at: XAML can’t read internal members, even if they’re located in
code.msdn.microsoft.com/mag201103Localization
the same assembly. To remedy this situation, the generated class
modifiers need to be changed to public. This can be accomplished
52 msdn magazine
in the design view of the resource file. The Access The final mandatory step in this process is to edit the
Modifier dropdown menu lets you designate the scope web.config file and add a globalization element inside
of the generated class. of the system.web element, setting the values of its
Once resource files are ready, you need to bind the attributes to auto:
resources in XAML. To do this you create a wrapper <globalization culture="auto" uiCulture="auto"/>
class with a static field referencing an instance of the As mentioned earlier, a Silverlight application has a
resource class. The class is as simple as this: neutral language setting. The setting is reached by going
public class StringResources { to the Silverlight tab of the project properties and clicking
private static readonly strings strings = new strings(); Figure 1 The App
public strings Strings { get { return strings; } }
Assembly Information. The neutral language property is
} located at the bottom of the dialog, as shown in Figure 3.
To make the class accessible from XAML, you need to create an I recommend setting the neutral language to one without a
instance. In this case, I’ll create the instance in the App class so that region. This setting is a fallback, and it’s more useful if it covers a
it’s accessible throughout the project: wide range of potential locales. Setting a neutral language adds an
<Application.Resources> assembly attribute to the assemblyinfo.cs file, like this:
<local:StringResources x:Key="LocalizedStrings"/>
[assembly: NeutralResourcesLanguageAttribute("en")]
</Application.Resources>
Data-binding in XAML is now possible. The XAML for the After all that, what you end up with is a localized application
TextBlock and the Image looks like this: that reads the browser language setting at startup and loads the
<StackPanel Grid.ColumnSpan="2" Orientation="Horizontal" appropriate resources.
HorizontalAlignment="Center">
<TextBlock Text="{Binding Strings.Welcome, Source={StaticResource
LocalizedStrings}}" A Custom Localization Process
FontSize="24"/>
</StackPanel>
The limitations of the standard localization process stem from the
<Image Grid.Row="1" Grid.ColumnSpan="2" use of ResourceManager and .resx files. The ResourceManager class
HorizontalAlignment="Center"
Source="{Binding Strings.FlagImage, Source={StaticResource
doesn’t change resource sets at run time based on culture changes
LocalizedStrings}}"/> within the environment. Using .resx files locks the developer into one
The path is the String property followed by the key of the resource resource set per language and inflexibility in maintaining the resources.
entry. The source is the instance of the StringResources wrapper In response to these limitations, let’s look at an alternative solu-
from the App class. tion that employs dynamic resources.
To make resources dynamic, the resource manager needs to send
Setting the Culture notification when the active resource set changes. To send notifica-
There are three application settings that must be configured for the tions in Silverlight, you implement the INotifyPropertyChanged
application to pick up the browser’s culture setting and display the interface. Internally, each resource set will be a dictionary with a
appropriate culture. key and value type of string.
The first setting is the SupportedCultures element in the .csproj The Prism framework and the Managed Extensibility Framework
file. Currently there’s no dialog box in Visual Studio to edit the (MEF) are popular for Silverlight development, and these frame-
setting, so the project file must be edited works break up the application into mul-
manually. You can edit a project file either tiple .xap files. For localization, each .xap
by opening it outside of Visual Studio, or file needs its own instance of the resource
by unloading the project and selecting edit manager. To send notifications to every
from the context menu within Visual Studio. .xap file (every instance of the resource
To enable English and French for this manager), I need to keep track of each
application, the value of the Supported- instance that gets created and iterate through
Cultures element looks like this: that list when notifications need to be sent.
<SupportedCultures>fr</SupportedCultures> Figure 4 shows the code for this Smart-
The cultures values are separated by com- ResourceManager functionality.
mas. You don’t need to specify the neutral As you can see, a static list is created to
culture; it’s compiled into the main DLL. hold all instances of the resource manager.
These next steps are necessary to pick up The active resource set is stored in the field
the browser language setting. A parameter resourceSet and every resource that has been
must be added to the embedded Silverlight loaded is stored in the ResourceSets list. In
object in the Web page. The parameters the constructor, the current instance is stored
value is the current UI culture, taken from in the Instances list. The class implements
the server side. This requires the Web page INotifyPropertyChanged in the standard
to be an .aspx file. The parameter syntax is: way. When the active resource set is changed,
<param name="uiculture"
value="<%=Thread.CurrentThread.
Figure 2 Project Structure After I iterate through the list of instances and fire
CurrentCulture.Name %>" /> Adding .resx Files each one’s PropertyChanged event.
msdnmagazine.com March 2011 53
the culture has already been loaded, the method simply sets the
corresponding resource set as active. The code to load a resource
is omitted for the moment.
For completeness, I’ll also show you the two methods to load
a resource programmatically (see Figure 5 ). The first method
takes just a resource key and returns the resource from the active
culture. The second method takes a resource and a culture name
and returns the resource for that specific culture.
If you ran the application right now, all localized strings would
be empty, because no resource sets have been downloaded. To
load the initial resource set, I’m going to create a method named
Initialize that takes the neutral language file and culture identifier.
This method should be called only once during the application
lifetime (see Figure 6).
Binding to XAML
A custom markup extension would provide the most fluid binding
syntax for the localized resources. Unfortunately, custom markup
extensions aren’t available in Silverlight. Binding to a dictionary is
available in Silverlight 3 and later, and the syntax looks like this:
Figure 3 Setting the Neutral Language
<StackPanel Grid.ColumnSpan="2" Orientation="Horizontal"
HorizontalAlignment="Center">
The SmartResourceManager class needs a way to change the culture <TextBlock Text="{Binding Path=ResourceSet[Welcome],
at run time, and it’s as simple as a method that takes a CultureInfo object: Source={StaticResource
SmartRM}}" FontSize="24"/>
public void ChangeCulture(CultureInfo culture) {
</StackPanel>
if (!ResourceSets.ContainsKey(culture.Name)) {
<Image Grid.Row="1" Grid.ColumnSpan="2"
// Load the resource set
HorizontalAlignment="Center"
}
Source="{Binding ResourceSet[FlagImage], Source={StaticResource SmartRM}}"/>
else {
ResourceSet = ResourceSets[culture.Name]; The path contains the name of the dictionary property with the
Thread.CurrentThread.CurrentCulture =
Thread.CurrentThread.CurrentUICulture =
key in square brackets. If you’re using Silverlight 2, there are two
culture; options available: creating a ValueConverter class or emitting a
}
}
strongly typed object using reflection. Creating a strongly typed
This method checks to see if the requested culture has been object using reflection is beyond the scope of this article. The code
loaded yet. If not, it loads the culture and then sets it as active. If for a ValueConverter would look like Figure 7.
The LocalizeConverter class takes the dictionary and parameter
Figure 4 SmartResourceManager passed in and returns the value of that key in the dictionary. After
creating an instance of the converter, the binding syntax would
public class SmartResourceManager : INotifyPropertyChanged {
private static readonly List<SmartResourceManager> Instances = look like this:
new List<SmartResourceManager>(); <StackPanel Grid.ColumnSpan="2" Orientation="Horizontal"
private static Dictionary<string, string> resourceSet; HorizontalAlignment="Center">
private static readonly Dictionary<string, <TextBlock Text="{Binding Path=ResourceSet, Source={StaticResource
Dictionary<string, string>> ResourceSets = SmartRM}, Converter={StaticResource LocalizeConverter},
new Dictionary<string, Dictionary<string, string>>(); ConverterParameter=Welcome}" FontSize="24"/>
</StackPanel>
public Dictionary<string, string> ResourceSet { <Image Grid.Row="1" Grid.ColumnSpan="2" HorizontalAlignment="Center"
get { return resourceSet; } Source="{Binding ResourceSet, Source={StaticResource SmartRM},
set { resourceSet = value; Converter={StaticResource LocalizeConverter}, ConverterParameter=FlagImage}"/>
// Notify all instances
foreach (var obj in Instances) { The syntax is more verbose using the converter, though you have
obj.NotifyPropertyChanged("ResourceSet"); more flexibility. However, for the rest of the article, I’ll continue
}
} without the converter, instead using the dictionary binding syntax.
}
Server-Side Components }
}
Now let’s create a database to store resources and a Windows The operation simply finds all resources whose LocaleId is equal
Communication Foundation (WCF) service to retrieve those to the cultureName parameter. The dataContext field is an instance
resources. In larger applications, you’d want to create data and busi- of the LINQ to SQL class hooked up to the SQL Server database.
ness layers, but for this example, I won’t be using any abstractions. That’s it! LINQ and WCF make things so simple.
Now, it’s time to link the WCF service to the SmartResource-
Figure 6 Initializing the Neutral Language Manager class. After adding a service reference to the Silverlight
public SmartResourceManager() { application, I register to receive the completed event for the
if (Instances.Count == 0) { GetResources operation in the constructor:
ChangeCulture(Thread.CurrentThread.CurrentUICulture);
}
Instances.Add(this); Figure 7 Custom ValueConverter
}
public class LocalizeConverter : IValueConverter {
public void Initialize(string neutralLanguageFile, public object Convert(object value,
string neutralLanguage) { Type targetType, object parameter,
lock (lockObject) { System.Globalization.CultureInfo culture) {
if (isInitialized) return; if (value == null) return string.Empty;
isInitialized = true;
} Dictionary<string, string> resources =
value as Dictionary<string, string>;
if (string.IsNullOrWhiteSpace(neutralLanguageFile)) { if (resources == null) return string.Empty;
// No neutral resources string param = parameter.ToString();
ChangeCulture(Thread.CurrentThread.CurrentUICulture);
} if (!resources.ContainsKey(param)) return string.Empty;
else {
LoadNeutralResources(neutralLanguageFile, neutralLanguage); return resources[param];
} }
} }
if (evt != null)
evt(this, new CultureChangeErrorEventArgs(
e.UserState as CultureInfo, e.Error));
}
else {
if (e.Result == null) return;
ResourceSets.Add(culture.Name, e.Result);
ResourceSet = e.Result;
Thread.CurrentThread.CurrentCulture =
Thread.CurrentThread.CurrentUICulture = culture;
}
}
Figure 9 Schema for Localization Tables in SQL Server 2008 Express
58 msdn magazine SilverLight Localization
Figure 11 Loading the Neutral Locale
public SmartResourceManager(string neutralLanguageFile, string neutralLanguage) {
Instances.Add(this);
localeClient.GetResourcesCompleted +=
localeClient_GetResourcesCompleted;
if (Instances.Count == 1) {
if (string.IsNullOrWhiteSpace(neutralLanguageFile)) {
// No neutral resources
ChangeCulture(Thread.CurrentThread.CurrentUICulture);
}
else {
LoadNeutralResources(neutralLanguageFile, neutralLanguage);
}
}
}
Wrapping Up
What I didn’t go over in this article was normalizing the resources on
the server side. Let’s say that the fr-FR resource is missing two keys that
the fr resource has. When requesting the fr-FR resources, the Web ser-
vice should insert the missing keys from the more general fr resource.
Another aspect that’s built into this solution that I didn’t cover is
loading resources by culture and resource set instead of just culture.
This is useful for loading resources per screen or per .xap file.
The solution I walked you through here does allow you to do a
few useful things, however, including loading resource sets at run
time, using any format for storing resources, changing resources
without recompiling and lazy loading resources.
The solution presented here is general-purpose, and you can
hook into it in multiple points and drastically change the imple-
mentation. I hope this helps reduce your daily programming load.
For further in-depth reading about internationalization, check
out the book “.NET Internationalization: The Developer’s Guide
to Building Global Windows and Web Applications” (Addison-
Wesley, 2006), by Guy Smith-Ferrier. Smith-Ferrier also has a great
video on internationalization on his Web site; the video is called
“Internationalizing Silverlight at SLUGUK” (bit.ly/gJGptU).
MATTHEW DELISLE enjoys studying both the software and hardware aspects of
computers. His first daughter was born in 2010 and he thinks she’s almost ready to
begin her programming career. Keep up with Delisle via his blog at mattdelisle.net.
Writing a Debugging
Tools for Windows
Extension
Andrew Richards
Troubleshooting production issues can be one of the contain a snapshot of a process memory at the time of capture.
most frustrating jobs that any engineer can do. It can also be one Depending on the dumping tool, this could be the entire address
of the most rewarding jobs. Working in Microsoft Support, I’m space or just a subset.
faced with this every day. Why did the application crash? Why did Windows automatically creates a minidump through Windows
it hang? Why is it having a performance issue? Error Reporting (WER) when any application throws an unhan-
Learning how to debug can be a daunting task, and is one of dled exception. In addition, you can manually create a dump
those skills that requires many hours of regular practice to stay file via the Userdump.exe tool. The Sysinternals tool ProcDump
proficient. But it’s a crucial skill for being an all-around developer. (technet.microsoft.com/sysinternals/dd996900) is becoming the preferred
Still, by bottling the skills of a few debugging experts, debugger process-dumping tool of Microsoft Support because it can capture
engineers of all skill levels can execute extremely complex debug- a dump based upon a large variety of triggers and can generate
ging logic as easy-to-run commands. dumps of various sizes. But once you have the dump data, what
Myriad troubleshooting techniques can be used to get to the can you do with it to aid debugging?
root cause of a crash, but the most valuable—and most fruitful to Various versions of Visual Studio support opening dump files
engineers with debugging skills—is a process dump. Process dumps (.dmp), but the best tool to use is a debugger from Debugging Tools
for Windows. These tools are all based on a single debugging engine
that supports two debugger extension APIs. In this article, I’m going
This article discusses:
to cover the basics of building a custom debugger extension so
• Debugging tools basics you can analyze these dump files (and also live systems) with ease.
• Using the debugger APIs
• Symbol resolution Setting up the Tools
• Dealing with processor types Debugging Tools for Windows (microsoft.com/whdc/devtools/debugging)
is an installable and redistributable component of the Windows
Technologies discussed:
SDK and Windows Driver Kit (WDK). As I write this, the current
Debugging Tools for Windows, C++ version is 6.12, and it’s available in version 7.1 of the Windows
Code download available at: SDK or the WDK. I recommend using the most-recent version,
code.msdn.microsoft.com/mag201103Debugger
as the debugging engine has many valuable additions, including
better stack walking.
60 msdn magazine
Figure 1 Sources Similarly, they use the wrong hardcoded register (esp in place of
TARGETNAME=MyExt
rsp, for example) instead of a pseudo-register such as $csp.
TARGETTYPE=DYNLINK If you’re having an issue with a debugger extension, you should
_NT_TARGET_VERSION=$(_NT_TARGET_VERSION_WINXP)
try running the debugger designed for the same architecture as the
target environment. This might overcome the assumptions of the
DLLENTRY=_DllMainCRTStartup
poorly written extension.
!if "$(DBGSDK_INC_PATH)" != "" Each application build type and associated processor architec-
INCLUDES = $(DBGSDK_INC_PATH);$(INCLUDES)
!endif
ture comes with its own set of debugging headaches. The assembler
!if "$(DBGSDK_LIB_PATH)" == "" generated for a debug build is relatively linear, but the assembler
DBGSDK_LIB_PATH = $(SDK_LIB_PATH)
!else
generated for a release build is optimized and can resemble a bowl
DBGSDK_LIB_PATH = $(DBGSDK_LIB_PATH)\$(TARGET_DIRECTORY) of spaghetti. On x86 architectures, Frame Pointer Omission (FPO)
!endif
plays havoc with call stack reconstruction (the latest debugger
TARGETLIBS=$(SDK_LIB_PATH)\kernel32.lib \ handles this well). On x64 architectures, function parameters and
$(DBGSDK_LIB_PATH)\dbgeng.lib
local variables are stored in registers. At the time of dump capture,
USE_MSVCRT=1 they may have been pushed onto the stack, or may no longer exist
UMTYPE=windows
due to register reuse.
Experience is the key here. To be accurate, one person’s experi-
MSC_WARNING_LEVEL = /W4 /WX
ence is the key here. You just need to bottle their know-how in a
SOURCES= dbgexts.rc \ debugger extension for the rest of us. It only takes a few repetitions
dbgexts.cpp \
myext.cpp
of a similar debugging sequence before I automate it as a debugger
extension. I’ve used some of my extensions so much that I forget how
I did the same thing using the underlying debugging commands.
The Debugging Tools for Windows guidelines say that you
should compile debugger extensions using the WDK build Using the Debugger APIs
environment. I use the latest release of the WDK (version 7.1.0 There are two debugger extension APIs: the deprecated WdbgExts
build 7600.16385.1), but any version of the WDK or its previous API (wdbgexts.h) and the current DbgEng API (dbgeng.h).
incarnation as the Driver Development Kit (DDK) will suffice. WdbgExts extensions are based on a global call that’s configured
When building an extension using the WDK, you use x64 and x86 at initialization (WinDbgExtensionDllInit):
Free Build environments. WINDBG_EXTENSION_APIS ExtensionApis;
With a little bit of effort you can also adapt my projects to build
Figure 2 dbgexts.cpp
in the Windows SDK build environment or Visual Studio.
One note of warning: The WDK doesn’t like spaces in path names. // dbgexts.cpp
Make sure you compile from an unbroken path. For example, use #include "dbgexts.h"
something like C:\Projects instead of C:\Users\Andrew Richards\
extern "C" HRESULT CALLBACK
Documents\Projects. DebugExtensionInitialize(PULONG Version, PULONG Flags) {
Regardless of how you build the extension, you’ll need the header *Version = DEBUG_EXTENSION_VERSION(EXT_MAJOR_VER, EXT_MINOR_VER);
*Flags = 0; // Reserved for future use.
and library files of the Debugging Tools SDK, which is a component return S_OK;
of Debugging Tools for Windows. The examples in this article use }
my x86 path (C:\debuggers_x86\sdk) when referencing the header extern "C" void CALLBACK
and library files. If you choose to install the debugger elsewhere, DebugExtensionNotify(ULONG Notify, ULONG64 Argument) {
UNREFERENCED_PARAMETER(Argument);
remember to update the path and add quotes when necessary to switch (Notify) {
accommodate spaces in the path names. // A debugging session is active. The session may not necessarily be suspended.
case DEBUG_NOTIFY_SESSION_ACTIVE:
break;
Using the Debugging Tools // No debugging session is active.
case DEBUG_NOTIFY_SESSION_INACTIVE:
The Debugging Tools for Windows debuggers are architecture- break;
agnostic. Any edition of the debugger can debug any target // The debugging session has suspended and is now accessible.
case DEBUG_NOTIFY_SESSION_ACCESSIBLE:
architecture. A common example is using the x64 debugger to break;
debug an x86 application. The debugger is released for x86, x64 // The debugging session has started running and is now inaccessible.
case DEBUG_NOTIFY_SESSION_INACCESSIBLE:
(amd64) and IA64, but it can debug x86, x64, IA64, ARM, EBC and break;
PowerPC (Xbox) applications. You can install all of the debugger }
return;
editions side-by-side. }
This agility isn’t universally understood, though. Not all debugger
extern "C" void CALLBACK
extensions adapt to the target architecture as well as the debugger DebugExtensionUninitialize(void) {
engine does. Some debugger extensions assume that the pointer return;
}
size of the target will be the same as the pointer size of the debugger.
msdnmagazine.com March 2011 61
The global provides the functionality required to run functions I’ve added the switch statement for the Notify parameter for
such as dprintf(“\n”) and GetExpression(“@$csp”) without any completeness, but I haven’t added any functional code in this area.
namespace. This type of extension resembles the code you’d write The switch statement processes four session state changes:
when doing Win32 programming. • DEBUG_NOTIFY_SESSION_ACTIVE occurs when you
DbgEng extensions are based on debugger interfaces. The attach to a target.
IDebugClient interface is passed to you by the debug engine as • DEBUG_NOTIFY_SESSION_INACTIVE occurs when
a parameter of each call. The interfaces support QueryInterface the target becomes detached (via .detach or qd).
for access to the ever-increasing range of debugger interfaces. • If the target suspends (hits a breakpoint, for example), the
This type of extension resembles the code you’d write when doing function will be passed DEBUG_NOTIFY_SESSION_
COM programming. ACCESSIBLE.
It’s possible to make a hybrid of the two extension types. You expose • If the target resumes running, the function will be passed
the extension as DbgEng, but add the functionality of the WdbgExts DEBUG_NOTIFY_SESSION_INACCESSIBLE.
API at run time via a call to IDebugControl::GetWindbgExtension- The DebugExtensionUninitialize function is called when the
Apis64. As an example, I’ve written the classic “Hello World” as a extension is unloaded.
DbgEng extension in C. If you prefer C++, refer to the ExtException Each extension command to be exposed is declared as a function
class in the Debugging Tools SDK (.\inc\engextcpp.cpp). of type PDEBUG_EXTENSION_CALL. The name of the function
Compile the extension as MyExt.dll (TARGETNAME in the is the name of the extension command. Because I’m writing “Hello
sources file shown in Figure 1 ). It exposes a command called World,” I’ve named the function helloworld (see Figure 3).
!helloworld. The extension dynamically links to the Microsoft Note that the convention is to use lower-case function names.
Visual C runtime (MSVCRT). If you want to use static, change the Because I’m using the WDK build environment, the myext.def file
USE_MSVCRT=1 statement to USE_LIBCMT=1 in the sources file. also needs to be changed. The name of the extension command
The DebugExtensionInitialize function (see Figure 2) is called needs to be added so that it’s exported:
when the extension is loaded. Setting the Version parameter is a ;-------------
; MyExt.def
simple matter of using the DEBUG_EXTENSION_VERSION ;-------------
macro with the EXT_MAJOR_VER and EXT_MINOR_VER EXPORTS
helloworld
#defines I’ve added to the header file: DebugExtensionNotify
// dbgexts.h DebugExtensionInitialize
DebugExtensionUninitialize
#include <windows.h>
#include <dbgeng.h>
The args parameter contains a string of the arguments for the
command. The parameter is passed as a null-terminated ANSI
#define EXT_MAJOR_VER 1
#define EXT_MINOR_VER 0
string (CP_ACP).
The Version value is reported as the API version in the debugger The pDebugClient parameter is the IDebugClient interface
.chain command. To change the File Version, File Description, pointer that allows the extension to interact with the debugging
Copyright and other values you need to edit the dbgexts.rc file: engine. Even though the interface pointer looks like it’s a COM
myext.dll: image 6.1.7600.16385, API 1.0.0, built Wed Oct 13 20:25:10 2010 Interface pointer, it can’t be marshaled, nor accessed at a later
[path: C:\Debuggers_x86\myext.dll] time. It also can’t be used from any other thread. To do work
The Flags parameter is reserved and should be set to zero. The on an alternate thread, a new debugger client (a new interface
function needs to return S_OK. pointer to IDebugClient) must be created on that thread using
The DebugExtensionNotify function is called when the session IDebugClient::CreateClient. This is the only function that can be
changes its active or accessible status. The Argument parameter is run on an alternate thread.
wrapped with the UNREFERENCED_PARAMETER macro to The IDebugClient interface (like all interfaces) is derived from
eliminate the unused parameter compiler warning. IUnknown. You use QueryInterface to access the other DbgEng
interfaces, be they later versions of the IDebugClient interface
Figure 3 MyExt.cpp (IDebugClient4) or different interfaces (IDebugControl, IDebug-
// MyExt.cpp Registers, IDebugSymbols, IDebugSystemObjects and so on). To
output text to the debugger, you need the IDebugControl interface.
#include "dbgexts.h"
I have two non-SDK files in the folder to help with develop-
HRESULT CALLBACK ment. The make.cmd script adds the Debugger SDK inc and lib
helloworld(PDEBUG_CLIENT pDebugClient, PCSTR args) {
UNREFERENCED_PARAMETER(args); paths to the WDK build environment, then runs the appropriate
build command:
IDebugControl* pDebugControl;
if (SUCCEEDED(pDebugClient->QueryInterface(__uuidof(IDebugControl), @echo off
(void **)&pDebugControl))) { set DBGSDK_INC_PATH=C:\Debuggers_x86\sdk\inc
pDebugControl->Output(DEBUG_OUTPUT_NORMAL, "Hello World!\n"); set DBGSDK_LIB_PATH=C:\Debuggers_x86\sdk\lib
pDebugControl->Release(); set DBGLIB_LIB_PATH=C:\Debuggers_x86\sdk\lib
} build -cZMg %1 %2
return S_OK; Note that the WDK build environment itself determines whether
}
an x86 or x64 binary will be built. If you want to build for multiple
62 msdn magazine Debugger APIs
/update/2011/03
www.componentsource.com
BEST
BEST SELLER
SELLER Spread for Windows Forms from $959.04
A comprehensive Excel compatible spreadsheet component for Windows Forms applications.
t4QFFEEFWFMPQNFOUXJUI4QSFBETIFFU%FTJHOFST
2VJDLTUBSU8J[BSEBOE$IBSU%FTJHOFST
t"VUPNBUJDDPNQMFUJPOQSPWJEFiUZQFBIFBEwGSPNVTFSJOQVUUPDFMM
t'FBUVSFTCVJMUJOUPPMUPEFTJHODIBSUTXJUIEJòFSFOUTUZMFT
t1SFTFSWFT&YDFMöMFTBOESFTUPSFTVOTVQQPSUFEGVODUJPOBMJUZ
t*ODMVEFTTMFFLOFXQSFEFöOFETLJOTBOEUIFBCJMJUZUPDSFBUFDVTUPNTLJOT
BEST
BEST SELLER
SELLER ActiveReports 6 from $685.02
Latest release of the best selling royalty free .NET report writer.
t/PXTVQQPSUT8JOEPXT4FSWFS
#JU*&
t'JSTU'MBTICBTFE3FQPSU7JFXFSGPSFOEVTFST
t4VQQPSUT1%'%JHJUBM4JHOBUVSFT
344#BS$PEFTBOEFYUFSOBMTUZMFTIFFUT
t'FBUVSFTBOFBTZUPVTF7JTVBM4UVEJPSFQPSUEFTJHOFSBOEBQPXFSGVM"1*
t0òFSTTFBNMFTTSVOUJNFEFQMPZNFOU
SPZBMUZGSFF
BESTSELLER
BEST SELLER TX Text Control .NET for Windows Forms/WPF from $499.59
Word processing components for Visual Studio .NET.
t"EEQSPGFTTJPOBMXPSEQSPDFTTJOHUPZPVSBQQMJDBUJPOT
t3PZBMUZGSFF8JOEPXT'PSNTBOE81'SJDIUFYUCPY
t5SVF8:4*8:(
OFTUFEUBCMFT
UFYUGSBNFT
IFBEFSTBOEGPPUFST
JNBHFT
CVMMFUT
TUSVDUVSFEOVNCFSFEMJTUT
[PPN
EJBMPHCPYFT
TFDUJPOCSFBLT
QBHFDPMVNOT
t-PBE
TBWFBOEFEJU%0$9
%0$
1%'
1%'"
35'
)5.-
595BOE9.-
The “Hello World” application may be amazing, but you can do When I run the scripts, the x86 debugger is launched, the
better. I’m now going to use this infrastructure to add a command appropriate dump file is opened, the x86 version of the extension
that actually interacts with the target and would help you do some is loaded and symbols are resolvable.
analysis. The simple test01 application has a global pointer that’s Once again, if everything has gone to plan, I can type “x test01!g_ptr”
assigned a value: and !gptr in the debugger command prompt and see similar responses:
// test01.cpp // x86 Target
0:000> x test01!g_ptr
#include <windows.h> 012f3370 Test01!g_ptr = 0x012f20e4
pointer. The pointer will be in a different location each time the IDebugSymbols* pDebugSymbols;
application runs because Address Space Layout Randomization if (SUCCEEDED(pDebugClient->QueryInterface(__uuidof(IDebugSymbols),
(void **)&pDebugSymbols))) {
(ASLR) will change the module load address. To get the location, // Resolve the symbol.
I use QueryInterface to get the IDebugSymbols interface, and then ULONG64 ulAddress = 0;
if (SUCCEEDED(pDebugSymbols->GetOffsetByName("test01!g_ptr", &ulAddress))) {
use GetOffsetByName. The GetOffsetByName function takes a IDebugDataSpaces* pDebugDataSpaces;
symbol name and returns the address as a 64-bit pointer. The if (SUCCEEDED(pDebugClient->QueryInterface(__uuidof(IDebugDataSpaces),
(void **)&pDebugDataSpaces))) {
debugger functions always return 64-bit pointers (ULONG64) so // Read the value of the pointer from the target address space.
that 64-bit targets can be debugged with a 32-bit debugger. ULONG64 ulPtr = 0;
if (SUCCEEDED(pDebugDataSpaces->ReadPointersVirtual(1, ulAddress,
Remember, this is the address of the pointer in the target address &ulPtr))) {
space, not your own. You can’t just read from it to determine its value. PDEBUG_CONTROL pDebugControl;
if (SUCCEEDED(pDebugClient->QueryInterface(__uuidof(IDebugControl),
To get the value of the pointer, I use QueryInterface again to get the (void **)&pDebugControl))) {
IDebugDataSpaces interface, and then use ReadPointersVirtual. This // Output the values.
pDebugControl->Output(DEBUG_OUTPUT_NORMAL,
reads the pointer from the target address space. ReadPointersVirtual "%p test01!g_ptr = 0x%p\n", ulAddress, ulPtr);
automatically adjusts for pointer size and endian differences. You don’t pDebugControl->Output(DEBUG_OUTPUT_NORMAL, "%ma\n", ulPtr);
pDebugControl->Release();
need to manipulate the pointer returned. }
IDebugControl::Output takes the same format string as printf, }
pDebugDataSpaces->Release();
but also has formatters that allow you to reference the target address }
space. I use the %ma format to print out the ANSI string that the pDebugSymbols->Release();
}
global pointer points to in the target address space. The %p format }
is pointer-size-aware and should be used for pointer output (you return S_OK;
}
must pass a ULONG64).
64 msdn magazine Debugger APIs
WINDOWS FORMS / WPF / ASP.NET / ACTIVEX
WORD PROCESSING
COMPONENTS
MILES BEYOND RICH TEXT
G
TRUE WYSIWY
F U L M A IL M ERGE
POWER
F IC E N O T R E QUIRED MEET US AT
MS OF HTML
, D O C , R T F &
PDF, DOCX
C O N N E C T I O N S
MARCH 27-30, 2011, ORLANDO
If you repeat the test using the x64 debugger, the amd64-compiled The first step is to get the stack frames. To get the frames, I use
version of the debugger extension and the x86 or x64 dump files, you’ll QueryInterface to get the IDebugControl interface, and then use
get the same results. That is, the extension is architecture-agnostic. GetStackTrace to retrieve information about each stack frame.
GetStackTrace takes an array of DEBUG_STACK_FRAME struc-
Processor Types and Stacks tures. I always allocate the array of DEBUG_STACK_FRAME
I’m now going to extend this infrastructure once again. Let’s add structures on the heap so that I don’t cause a stack overflow. If you’re
a command that finds the duration of a Sleep call on the current retrieving a stack overflow thread of a target, you’ll probably hit
thread stack. The !sleepy command (see Figure 5 ) will resolve your own stack limit if the array is allocated on your stack.
the call stack symbols, look for the Sleep function and read the If GetStackTrace succeeds, the array will be populated with
DWORD that represents the milliseconds to delay, and then will information for each frame that was walked. Success here doesn’t
output the delay value (if found). necessarily mean that the frame information is correct. The
To add some complexity to the command, the command will sup- debugger does its best to walk the stack frames, but mistakes can
port the x86 and x64 versions of the test01 application. Because the be made when the symbols aren’t correct (when they’re missing or
calling convention is different for x86 and x64 applications, the com- have been forced). If you’ve used “.reload /f /i” to force the symbol
mand will have to be aware of the target’s architecture as it progresses. load, poor symbol alignment will probably occur.
66 msdn magazine Debugger APIs
Project3 12/16/09 11:55 AM Page 1
To effectively use the contents of each of the DEBUG_STACK_ There are two parts to the symbol: the symbol name
FRAME structures, I need to know the target’s effective proces- (KERNELBASE!Sleep) and the displacement (0xf). The symbol
sor type. As mentioned previously, the target architecture can be name is an amalgamation of the module name and the function
completely different from the debugger extension architecture. The name (<module>!<function>). The displacement is the byte offset
effective processor type (.effmach) is the architecture that the from the start of the function to which program flow will return to
target is currently using. after the call has returned.
The processor type can also be a different processor type than that If there are no symbols, the function will be reported as just the
used by the target’s host. The most common example of this is when module name with a large displacement (Test01+0x1015).
the target is an x86 application that’s running via Windows 32-bit Once I’ve found the frame, the next step is to extract the delay.
on Windows 64-bit (WOW64) on an x64 edition of Windows. The When the target is x86 based, the delay will be in a DWORD that
effective processor type is IMAGE_FILE_MACHINE_I386. The has been pushed onto the stack immediately prior to the function
actual type is IMAGE_FILE_MACHINE_AMD64. call (note that this is fragile logic):
This means you should consider an x86 application to be an x86 // @$csp is the pseudo-register of @esp
0:000> dps @$csp
application regardless of whether it’s running on an x86 edition <snip>
of Windows or an x64 edition of Windows. (The only exception 001bfa4c 752c1818 KERNELBASE!Sleep+0xf
001bfa50 00002710
to this rule is when you’re debugging the WOW64 calls that <snip>
surround the x86 process.) The StackOffset member of the DEBUG_STACK_FRAME
To get the effective processor type, I use the IDebugControl in- structure actually points to this address already, so no pointer
terface that I already have, and then use GetEffectiveProcessorType. arithmetic is necessary. To get the value, I use QueryInterface to
If the effective processor type is i386, I need to look for the get the IDebugDataSpaces interface, and then use ReadVirtual to
KERNELBASE!Sleep+0xf function. If all the symbols are resolved read the DWORD from the target address space.
correctly, the function should be in frame 3: If the target is x64 based, the delay isn’t in the stack—it’s in
0:000> knL4
# ChildEBP RetAddr
the rsi register (this is also fragile logic due to its frame-context
00 001bf9dc 76fd48b4 ntdll!KiFastSystemCallRet dependency):
01 001bf9e0 752c1876 ntdll!NtDelayExecution+0xc 0:000> r @rsi
02 001bfa48 752c1818 KERNELBASE!SleepEx+0x65 rsi=0000000000002710
03 001bfa58 012f1015 KERNELBASE!Sleep+0xf
To get the value, I use QueryInterface to get the IDebugRegisters
If the effective processor type is AMD64, I look for the
interface. I first need to use GetIndexByName to get the index of
KERNELBASE!SleepEx+0xab function. If all the symbols are
the rsi register. I then use GetValue to read the register value from
resolved correctly, the function should be in frame 1:
0:000> knL2
the target registers. Because rsi is a 64-bit register, the value is
# Child-SP RetAddr Call Site returned as an INT64. Because the DEBUG_VALUE structure is a
00 00000000'001cfc08 000007fe'fd9b1203 ntdll!NtDelayExecution+0xa
01 00000000'001cfc10 00000001'3fda101d KERNELBASE!SleepEx+0xab
union, you can simply reference the I32 member instead of the I64
However, based on the level of symbol resolution available, the member to get the truncated version that represents the DWORD
function symbol I’m looking for may or may not be in the expected passed to Sleep.
frame. If you open the test01 x86 dump file and don’t specify a sym- Once again, in both cases, I use the IDebugControl::Output
bol path, you can see an example of this. The KERNELBASE!Sleep function to output the result.
call will be in frame 1 instead of frame 3:
0:000> knL4 Break!
# ChildEBP RetAddr In this article, I barely scratched the surface of what can be achieved.
WARNING: Stack unwind information not available. Following frames may be wrong.
00 001bfa48 752c1818 ntdll!KiFastSystemCallRet Stacks, symbols, registers, memory I/O and environmental infor-
01 001bfa58 012f1015 KERNELBASE!Sleep+0xf mation are but a few of the many things that you can interrogate
02 001bfaa4 75baf4e8 Test01+0x1015
03 001bfab0 76feaf77 kernel32!BaseThreadInitThunk+0x12 and change from within an extension.
The debugger warns you of this possible mistake. If you want to In a future article I’ll delve deeper into the relationship a debug-
have your extension adapt to these types of issues, you should iterate ger extension can have with the debugger. I’ll cover debugger
over the frames as I have, instead of just looking at the expected frame. clients and debugger callbacks, and I’ll use these to encapsulate
To determine the existence of the Sleep function, I need to look the SOS debugger extension so that you can write an extension
up the symbol for each frame. If the effective processor type and that can debug managed applications without having to have any
symbol make a valid pair, the function has been found. Note that knowledge of the underlying .NET structures.
this logic is fragile and is being used to simplify the example. The
symbol may change between builds and platforms. For example, ANDREW RICHARDS is a Microsoft senior escalation engineer for Exchange Server.
Windows Server 2008 is kernel32!Sleep+0xf, but Windows 7 is He has a passion for support tools, and is continually creating debugger extensions
and applications that simplify the job of support engineers.
KERNELBASE!Sleep+0xf.
To get the symbol, I use QueryInterface to get the IDebugSymbol THANKS to the following technical experts for reviewing this article:
interface. I then use GetNameByOffset to get the symbol of the Drew Bliss, Jen-Lung Chiu, Mike Hendrickson, Ken Johnson, Brunda
instruction offset address. Nagalingaiah and Matt Weber
www.SpreadsheetGear.com.
Toll Free USA (888) 774-3273 | Phone (913) 390-4797 | sales@spreadsheetgear.com
Building Data-Centric
Web Apps with ASP.NET
MVC and Ext JS
Juan Carlos Olamendy
A rich Internet application (RIA) combines the usability with Selenium for testing. Ext JS also provides pre-defined controls
of a desktop app with the flexibility of Web-based deployment that simplify creating the UI of your Web app.
and revision. There are two key approaches to building RIAs. Unfortunately, most examples of Ext JS are illustrated with
First, there are browser plug-ins that host execution environ- PHP, Python and Ruby on Rails code on the server side. But that
ments such as Flash, Java and Silverlight. Second, there are doesn’t mean developers using Microsoft technologies can’t take
JavaScript-based extension libraries such as Dojo, Ext JS, jQuery, advantage of Ext JS. While it’s difficult to integrate Ext JS with Web
MooTools, Prototype and YUI. Each approach has its advantages Forms development (due to the abstraction layer that encapsulates
and disadvantages. the request-response nature of the Web in order to provide a
JavaScript libraries are a popular choice for building RIAs stateful control-based model), you could use the ASP.NET MVC
because JavaScript is supported by all major browsers and there’s no framework, enabling you to leverage both the Microsoft .NET
need to install a plug-in or runtime environment. I’ve been experi- Framework and Ext JS in the same app.
menting with another of the libraries mentioned—Ext JS—and I’ve In this article, I’ll provide the tutorial I couldn’t find, walking
found that it makes an interesting choice for implementing Web through the development of a real-world Web solution using ASP.NET
apps. It’s easy to implement, well-documented and is compatible MVC and Ext JS that reads from and writes to a back-end database.
to one employee.
age int,
salary numeric(8,2) not null,
deptno varchar(20) not null,
constraint fk_employee_department_belong_rltn foreign key(deptno)
references department(deptno)
); To customize the error messages on the fields, add the following
create unique index undx_employee_fullname on employee(fullname); line of code just under the Ext.onReady function:
Ext.QuickTips.init();
Another way to declare controls is on the fly: Now, when the user moves the mouse pointer over the field, a
items: [ balloon with a message displaying the error is displayed.
{ fieldLabel: 'Name', emptyText: 'Please, enter a name', name: 'name' },
{ xtype: 'numberfield', fieldLabel: 'Age', value: '25', name: 'age' }
I set several validation rules for the fields such as specifying the
] minimum and maximum length allowed, deferring the field vali-
As you can see, for the name field you don’t have to specify the dation until form submission, and creating validation functions
type because it’s taken from the default properties of the form. for URLs, e-mail addresses, and other types of data. You can see
I’ll add some additional elements to the form, which ends up the details of this validation in the code download.
looking like Figure 1.
So far, you’ve built a form using Ext JS to take data from the user. Building the Web App
Now, let’s send the data to the server. You’ll need to add a button Now, let’s develop a Web solution using Ext JS and ASP.NET MVC.
to handle the submit process and show the result to the user, as I used ASP.NET MVC 2, but this solution should be applicable
shown in Figure 2. to ASP.NET MVC 3 as well. The scenario I’m going to address is
The buttons property enables the form to manage all the possible adding an employee in a human resources management system.
actions. Each button has name and handler properties. The handler
Figure 5 Adding the Employee Form
Figure 4 Site.Master <%@ Page Title="" Language="C#"
MasterPageFile="~/Views/Shared/Site.Master"
<head runat="server"> Inherits="System.Web.Mvc.ViewPage" %>
<title><asp:ContentPlaceHolder ID="TitleContent"
runat="server" /></title> <asp:Content ID="Content1" ContentPlaceHolderID="TitleContent"
<link href="../../Content/Site.css" rel="stylesheet" runat="server">
type="text/css" /> Index
</asp:Content>
<!-- Include the Ext JS framework -->
<link href="<%= Url.Content("~/Scripts/ext-3.2.1/resources/css/ext-all.css") %>" <asp:Content ID="Content2" ContentPlaceHolderID="MainContent"
rel="stylesheet" type="text/css" /> runat="server">
<script type="text/javascript" <h2>Add a New Employee</h2>
src="<%= Url.Content("~/Scripts/ext-3.2.1/adapter/ext/ext-base.js") %>"> <div id="employeeform"></div>
</script> </asp:Content>
<script type="text/javascript"
src="<%= Url.Content("~/Scripts/ext-3.2.1/ext-all.js") %>"> <asp:Content ID="Content3" ContentPlaceHolderID="Scripts"
</script> runat="server">
<!-- Placeholder for custom JS and CSS and JS files <script type="text/javascript"
for each page --> src="<%= Url.Content("~/Scripts/employee_form.js") %>">
<asp:ContentPlaceHolder ID="Scripts" runat="server" /> </script>
</head> </asp:Content>
namespace HumanResources_ExtJSASPNETMVC.Models.BusinessObjects { Now let’s go back to Ext JS and use the framework to build the
public class HumanResourcesController : Controller {
DepartmentRepository _repoDepartment = new DepartmentRepository(); presentation layer of the application. For this solution, you only
EmployeeRepository _repoEmployee = new EmployeeRepository(); need to import ext-all.js and the \adapter and \resources folders.
// GET: /HumanResources/ Go to the Site.Master page and add references to the Ext JS files
public ActionResult Index() {
return View();
inside the head element, as well as an <asp:ContentPlaceHolder>
} tag element as a container of the customized JavaScript and CSS
// POST: /HumanResource/Departments code for each page, as shown in Figure 4.
[HttpPost] Now let’s add the other important pieces of the MVC architec-
public ActionResult Departments() {
var arrDepartment = this._repoDepartment.FindAll(); ture: the view. The view will present the form to get the data related
var results = (new { to one employee. Go to HumanResourcesController, right-click
departments = arrDepartment
}); on the Index action method and select Add View. Click the Add
return Json(results); button in the Add View dialog box.
}
To implement the Ext JS form created earlier in the article,
// POST: /HumanResource/AddEmployee you need to add a JavaScript file to the Scripts directory and a
[HttpPost]
public ActionResult AddEmployee(employee employee) { reference to this JavaScript file in the view. Then include the
string strResponse = String.Empty; reference to the employee_form.js file and add a div element into
try {
this._repoEmployee.Create(employee); the Index.aspx view (see Figure 5).
strResponse = "{success: true}"; Go to the employee_form.js file and add some code to configure
}
catch { the ExtJS form and its underlying widgets. The first step is to define
strResponse = "{success: false, error: \"An error occurred\"}"; an instance of Ext.data.JsonStore class to get a list of departments:
}
return Content(strResponse); var departmentStore = new Ext.data.JsonStore({
} url: 'humanresources/departments',
} root: 'departments',
} fields: ['deptno', 'deptname']
});
That’s It!
Now run the solution. You’ll see the Web page shown in Figure
8. Enter some data in the form and then click Add. You’ll see a
confirmation message box. You’ll also see the row inserted in the
dbo.employee table on the database.
That’s really all there is to creating a simple RIA. Depending on
the features you want to leverage, a similar application could be
built with any of the other popular JavaScript frameworks while
still employing ASP.NET MVC. You could easily substitute Entity
Framework for the data layer, and use Windows Azure storage or
SQL Azure as the back-end data store. These simple building blocks
make building a basic data-centric RIA quick and easy.
If you’re a Web developer, in the past you may have utilized The ASP.NET output cache uses an in-memory storage mecha-
the output-caching facility provided by ASP.NET. Introduced nism and, until the .NET Framework 4, it wasn’t possible to override
with the first version of the Microsoft .NET Framework, ASP.NET or replace the default cache with your own implementation. With
output caching can improve the performance of serving content the new OutputCacheProvider type, it’s now possible to implement
to site visitors by retrieving that content from a cache, bypassing your own mechanism for caching page output in ASP.NET.
re-execution of pages or controllers. This saves your application In this article, I’ll discuss two such custom mechanisms. First,
expensive database calls when returning data that doesn’t update using MongoDB—a popular document-oriented database—I’ll
frequently, or that can be stale for periods of time. create my own provider to facilitate output caching in a simple
ASP.NET MVC application. Then, using the same application,
I’ll quickly swap out my custom provider to leverage features of
This article discusses a prerelease version of Windows Azure Windows Azure AppFabric—specifically, the new DistributedCache
AppFabric SDK 2.0. All information is subject to change.
provider that leverages Windows Azure infrastructure to provide
This article discusses: a distributed, in-memory cache in the cloud.
• Output caching in ASP.NET
• Extensible output caching in ASP.NET
Output Caching in ASP.NET
In ASP.NET Web Forms applications, output caching can be con-
• NoSQL, document databases and MongoDB
figured by adding an OutputCache Page directive to any ASP.NET
• Building a custom OutputCacheProvider using MongoDB page or user control:
• Using the MongoDB OutputCacheProvider in ASP.NET MVC <%@ OutputCache Duration="60" Location="Any" VaryByParam="name" %>
• Using the Windows Azure AppFabric DistrubutedCache provider For ASP.NET MVC applications, output caching is available
using an action filter that ships with ASP.NET MVC, and which
Technologies discussed:
can be leveraged as an attribute on any controller action:
ASP.NET 4, Windows Azure, MongoDB [OutputCache(Duration=60, VaryByParam="none")]
Code download available at: “Duration” and “VaryByParam” are required in ASP.NET MVC 1
code.msdn.microsoft.com/mag201103OutputCache
and 2 applications (VaryByParam is optional in ASP.NET MVC 3),
and both mechanisms provide several other attributes and parameters
76 msdn magazine
Browser requests page Yes Retrieve page from Has item Yes Retrieve page from
(with OutputCache Does page exist cache by key cache by key
in cache? expired?
directive or attribute) (path + parameters) (path + parameters)
No No
that enable developers to control how content is cached (several Although the .NET Framework 2.0 and 3.0 introduced several
VaryByX parameters), where it’s cached (Location) and capabilities enhancements to the default cache provider, the provider itself
for setting cache invalidation dependencies (SqlDependency). remained the same: an in-memory store, with no extension points
For traditional output caching, nothing else is needed to imple- or way to provide your own implementation. The in-memory cache
ment this functionality in your applications. The OutputCache type is a perfectly acceptable option in most cases, but can, at times,
is an HttpModule that runs when your application starts and goes to contribute to diminished site performance as server resources
work when a page directive or action filter is encountered. Upon the are maxed out and memory becomes scarce. What’s more, the
first request of the page or controller in question, ASP.NET will take default caching provider mechanism automatically evicts cached
the resulting content (HTML, CSS, JavaScript files and so on) and resources—regardless of specified duration—when memory does
place each item in an in-memory cache, along with an expiration become scarce, which leaves the developer with little control over
and a key to identify that item. The expiration is determined by the how cached resources are managed.
Duration property, and the key is determined by a combination of
the path to the page and any necessary VaryBy values—for example, Extensible Output Caching in ASP.NET
query string or parameter values if the VaryByParam property is The release of the .NET Framework 4 introduced a new facility that
provided. So, consider a controller action defined in this manner: enables developers to create their own output cache providers and
[OutputCache(Duration=20, VaryByParam="vendorState")]
easily plug those providers into new or existing applications with
Public ActionResult GetVendorList(string vendorState) only minor changes to the application and its configuration. These
{
// Action logic here.
providers are free to use whatever storage mechanism for cached
} information that they choose, such as local disks, relational and non-
In this case, ASP.NET will cache an instance of the resulting relational databases, the cloud or even distributed caching engines
HTML view for each occurrence of vendorState (for example, one such as that provided in Windows Server AppFabric. It’s even possible
for Texas, one for Washington and so on) as that state is requested. to use multiple providers for different pages in the same application.
The key by which each instance is stored, in this case, will be a
}
return null;
Building a Custom OutputCacheProvider
public override void Set(string key, object entry, DateTime utcExpiry)
Using MongoDB
{ To get started, you’ll want to go to mongodb.org to download and
return; install the tool. The documents at mongodb.org/display/DOCS/Quickstart
}
should tell you everything you need to know to install MongoDB on
public override void Remove(string key) Windows, Mac OS X and Unix. Once you’ve downloaded MongoDB
{
return; and tested things out with the shell, I recommend installing the
} database as a service using the following command from the instal-
}
lation directory (be sure to run cmd.exe as an administrator):
C:\Tools\MongoDB\bin>mongod.exe --logpath C:\Tools\MongoDB\Logs
Once you’ve implemented these four methods, all that’s left is to --directoryperdb --install
add the new provider to your web.config, specify it as the default MongoDB will install itself as a service on your computer and
and add an OutputCache directive or attribute to your application. will use C:\Data\db as the default directory for all its databases. The
I’ll cover these steps in detail as I walk through the creation of our option --diretoryperdb tells MongoDB to create a root directory
own output cache provider that uses a document database called for every database you create.
MongoDB. But first, it may be helpful to introduce a little context After running the previous command, type the following to
around the tool we’ll be using to build our custom provider. start the service:
net start MongoDB
NoSQL, Document Databases and MongoDB Once you have things up and running, you’ll need to install a
For much of the past few decades, the preferred application storage driver library to work with MongoDB in .NET. There are several
mechanism has been the relational database management system options available; I’ll be using the mongodb-csharp driver created
(RDBMS), which stores data and relationships in tables. SQL Server by Sam Corder (github.com/samus/mongodb-csharp).
and Oracle are examples of RDBMSes, as are most of the popular We have MongoDB installed, and we have a driver that we
commercial and open source databases currently in use. can use within a .NET application, so now it’s time to create our
However, not all problems requiring storage fit into the same custom output cache provider. To do this, I created a new class
transactional mold. In the late ’90s, as the Internet expanded and library called DocumentCache and added two classes: Document-
many sites grew to manage large volumes of data, it became obvi- DatabaseOutputCacheProvider and CacheItem.
ous that the relational model provided less-than-ideal performance The first is my provider, a public class that subclasses the
on certain types of data-intensive applications. Examples include abstract OutputCacheProvider. The beginning implementation is
indexing large volumes of documents, delivering Web pages on depicted in Figure 2.
high-traffic sites or streaming media to consumers. Figure 3 Implementing the Add Method
Many companies addressed their growing storage needs by
public override object Add(string key, object entry, DateTime utcExpiry)
turning to NoSQL databases, a class of lightweight database that {
doesn’t expose a SQL interface, fixed schemas or pre-defined key = MD5(key);
var item = _cacheItems.FindOne(new { _id = key });
relationships. NoSQL databases are used heavily by companies if (item != null) {
such as Google Inc. (BigTable), Amazon.com Inc. (Dynamo) and if (item.Expiration.ToUniversalTime() <= DateTime.UtcNow) {
_cacheItems.Remove(item);
Facebook (which has a store of more than 50TB for inbox searches) } else {
and are experiencing steady growth in popularity and use. return Deserialize(item.Item);
}
It’s important to note that, while some have used the term NoSQL }
as a rallying cry to call for the abandonment of all RDBMSes,
_cacheItems.Insert(new CacheItem
others emphasize the value of utilizing both types of storage. {
NoSQL databases were conceived to solve a class of problem Id = key,
Item = Serialize(entry),
that RDBMSes couldn’t—not to replace these systems outright. Expiration = utcExpiry
The discriminating developer would be wise to understand both });
systems and utilize each where appropriate, even at times mixing return entry
}
both types of storage in a single application.
78 msdn magazine Cache Integration
Notice that the second private variable in Figure 2 references Figure 4 Implementing the Get Method
CacheItem, the other class I need to create in my project. CacheItem public override object Get(string key)
exists to contain the relevant details that my output cache provider {
key = MD5(key);
needs to work with both ASP.NET and my database, but it isn’t an var cacheItem = _cacheItems.FindOne(new { _id = key });
object needed external to my provider. As such, I define CacheItem
if (cacheItem != null) {
as an internal class, as shown here: if (cacheItem.Expiration.ToUniversalTime() <= DateTime.UtcNow) {
[Serializable] _cacheItems.Remove(cacheItem);
internal class CacheItem } else {
{ return Deserialize(cacheItem.Item);
public string Id { get; set; } }
public byte[] Item { get; set; } }
public DateTime Expiration { get; set; }
} return null;
Id maps to the key provided to me by ASP.NET. You’ll recall that }
Using the
DistributedCache
Provider
So what if everything I’ve discussed
so far is more than you’d care to dive
into? Perhaps you want to leverage an
alternative caching mechanism, but
you have neither the time nor the de-
sire to roll your own? You’ll be happy
to know that, since the introduction
Figure 7 Windows Azure AppFabric Labs Summary Page of extensible output caching, many
80 msdn magazine Cache Integration
alternatives—commercial, open source and provided by Microsoft— Next, create the <dataCacheClient> section, replacing the
are either available or in development. One such example is a <host> name, cachePort and <messageSecurity> authorizationInfo
cloud-based, distributed in-memory cache: the DistributedCache properties with details from your portal account, like so:
provider currently available as a part of Windows Azure AppFabric. <dataCacheClient deployment="Simple">
<hosts>
If you’re already building cloud-based applications, Windows <host name="yournamespace.cache.appfabriclabs.com" cachePort="your port" />
Azure AppFabric Caching can speed up access to data for those </hosts>
<securityProperties mode="Message">
applications and, because caching is delivered as a cloud service, <messageSecurity authorizationInfo="your authentication token">
the setup is simple and requires no overhead to maintain. </messageSecurity>
</securityProperties>
At the time of this writing, AppFabric Caching is part of the </dataCacheClient>
Windows Azure AppFabric Community Technology Preview Then, find the <caching> section under <system.web> and add
October Release, so you can access caching features without an the following provider entry after the entry you created for your
active Windows Azure account. However, if you’re an MSDN custom provider:
subscriber, I highly recommend activating your Windows Azure <add name="DistributedCache"
benefits at windows.azure.com. Go to portal.appfabriclabs.com and create type="Microsoft.Web.DistributedCache.DistributedCacheOutputCacheProvider,
Microsoft.Web.DistributedCache"
an account to use the developer preview features. cacheName="default" />
Once you’ve created a Labs account, click on the Add Service Finally, change the defaultProvider attribute on the <outputCache>
Namespace link to enable AppFabric services (see Figure 7). element to “DistributedCache.” The DistributedCacheOutput-
After you’ve set up your service namespace, click on the Cache CacheProvider is a subclass type of the abstract OutputCache-
link, and take note of the service URL and authentication token listed Provider, just like our MongoDB implementation. Now, build and
in the cache section (see Figure 8). You’ll need this information to run your application and navigate to the Top Customers page. Try
configure your application to use the DistributedCache provider. adding a customer while the list is still cached and notice that, as
Next, you’ll need to download and install the Windows Azure with our MongoDB implementation, the list will remain cached
AppFabric SDK (click the download link on the Cache page in the as long as you specify.
portal). After the installation is complete, you’re ready to configure
Windows Azure AppFabric Caching for your application. Wrapping Up
You’ll need to add references to several assemblies that the SDK In this article, I discussed ASP.NET output caching, classical
installation placed on your machine. Using the same ASP.NET uses of the default in-memory cache, and new extensible caching
MVC application you used for your custom Document database facilities provided using the OutputCacheProvider abstract class
cache, navigate to the SDK install location (default is C:\Program in the .NET Framework 4. I talked about NoSQL and document
Files*\Windows Azure AppFabric SDK\V2.0\Assemblies\Cache) databases and how these types of systems are ideal for working
and add references to each assembly contained within. with transient data, such as cached output. We used MongoDB
Once you’ve done that, open your web.config and add the following to build a sample output cache and used that within an ASP.NET
<configSections> entry, keeping any existing configuration sections: MVC application. Finally, we moved our output cache to the
<configSections> cloud, and with minor setup and configuration and no code
<section name="dataCacheClient"
type="Microsoft.ApplicationServer.Caching.DataCacheClientSection, changes whatsoever, we were able to swap out caching mecha-
Microsoft.ApplicationServer.Caching.Core" nisms in our application.
allowLocation="true" allowDefinition="Everywhere"/>
</configSections> Extensible output caching is just one of the many great new
features in ASP.NET 4, and I hope
this exploration of the feature—
and of the technologies that can
be leveraged along with it—has
been useful. To learn more about
MongoDB, go to mongodb.org. To learn
more about Windows Azure App-
Fabric, go to portal.appfabriclabs.com/
helpandresources.aspx.
attribute in the DefaultTask on the WMAppManifest.xml application • Handling of the hardware Back button presses.
manifest, as shown here: • Providing events for page lifecycle to know when a page is
<Tasks>
<DefaultTask Name ="_default" NavigationPage="MainPage.xaml"/>
activated/deactivated.
</Tasks> For integration with the hardware Back button, PhoneApplication-
Getting a bit closer to responsibilities and APIs, PhoneApplication- Page exposes a BackKeyPress event. The page also has a virtual
Frame exposes most of the navigation methods and events we’ll OnBackKeyPress method you can override in your instance of a
need for this article. Figure 2 lists the most relevant methods, page to handle and even cancel a Back button press event.
properties and events in PhoneApplicationFrame. PhoneApplicationFrame has a Navigating event and an OnNavi-
Most are inherited from Frame, so for those familiar with the gatingFrom notification/callback. Within both of these, you can
Silverlight Frame class, these methods should look familiar. The cancel navigations to other pages within the app by setting e.Cancel
list in Figure 2 isn’t inclusive of all PhoneApplicationFrame = true in the NavigationCancelEventArgs parameter passed to these
features, just the relevant ones for navigation. methods; due to a known bug on the platform, you shouldn’t can-
Code Walk-Through: To see all these events and properties cel Back button navigations from these events/methods. If you do
in action, explore AllNavigations-
Events.xaml.cs in the sample code
accompanying this article. You can Page1 Page2 Page3
also see the order in which events
fire in Figure 3.
Navigate
PhoneApplicationFrame also (Page1.xaml) OnNavigationTo
determines the client area that the Loaded Navigate
application will get and reserves (Page2.xaml) OnNavigationTo
the space for the application bar OnNavigationFrom Loaded Navigate
and the system tray. This detail (Page3.xaml)
will be relevant as we navigate OnNavigationFrom OnNavigationTo
Loaded
across pages that have an appli-
GoBack
cation bar because it’s specified OnNavigationTo OnNavigationFrom
at the page level, and there’s a Loaded
system-wide animation to show OnNavigationTo
GoBack
OnNavigationFrom
and hide the application bar as a GoBack Loaded
page gets loaded. (Exits app)
The second participant in the nav- OnNavigationFrom
igation is PhoneApplicationPage. It
plays two critical roles in navigation: Figure 3 The Sequence of Events as You Navigate Across Pages
msdnmagazine.com March 2011 83
Figure 4 Events and Methods Where Navigations Can Be Canceled in the back stack. Also notice
Can Cancel a Can Cancel Back that NavigatedTo always fires
Owner Event/Notification New Navigation Navigations Check for Back Navigations before a page is loaded, so don’t
PhoneApplicationFrame Navigating Yes No Yes; check e.NavigationMode assume the contents of the
!= NavigationMode.Back page are loaded at this time.
PhoneApplicationPage OnNavigatingFrom Yes No Yes; check e.NavigationMode The reason OnNavigatedTo
!= NavigationMode.Back and OnNavigatedFrom are
PhoneApplicationPage OnBackKeyPress No (called only Yes Not needed; only called on critical to Windows Phone is
when Back key hardware Back key press because of the back stack. The
press is called) OS maintains the back stack
PhoneApplicationPage BackKeyPress No (called only Yes Not needed; only called on for pages you can go back to, so
(event) when Back key hardware Back key press
pages aren’t immediately un-
press is called)
loaded, destroyed or garbage
collected when a navigation
cancel a hardware Back button press in this event, your navigation happens from one page to another. Instead, the pages are moved to
will break and the application will need to be restarted. The only the back stack and kept alive (in memory), and when the user clicks
two recommended methods for canceling a hardware Back but- back to get to that page, the page is simply added back into the visual
ton press are the PhoneApplicationPage BackKeyPress event and tree. The page isn’t recreated (unless the application has been deacti-
the OnBackKeyPress callback. vated and tombstoned between when the user left the page and clicked
See Figure 4 for a list of events and methods where navigations back). Because forward journaling isn’t supported, pages are eligible
can be canceled, with recommendations on whether a Back press for garbage collection when you navigate from a page back to the
can be canceled in that method, and advice on how to check if the previous page—assuming there are no other references to this page.
event was a back navigation. Figure 5 shows a diagram that illustrates a PhoneApplication-
PhoneApplicationPage complements these events to complete Page lifecycle.
the navigation lifecycle with the more useful OnNavigatedTo and As you navigate from Page1 to Page2 and then Page3, pages aren’t
OnNavigatedFrom method callbacks for the page. To better under- garbage collected until you call the GoBack method from the page.
stand and easily remember when these callbacks are called, it’s best Inactive pages are in the back stack, but still in memory. If these
to complete their method names with a “this page.” One method pages are listening to global events, the event listeners are still active.
is called when the user has “navigated to this page,” and later the Despite a page not getting garbage collected when you navigate
other method gets called when the user is “navigated from this from it, the page is no longer visible or active until you navigate
page” onto another page. back to it, so you should make sure you do any cleanup and release
Figure 3 shows the sequence of events as you navigate across any expensive resources when the user has navigated away from
pages. The symmetry between NavigatedTo/NavigatedFrom makes a page. For example, if you’re listening to location changes using
these two methods ideal for starting and stopping work that’s GeoCoordinateWatcher, you should stop the listener on the
required when the page is visible, but not required when the page is OnNavigatedFrom and restart it when the user navigates back to
your page–and your page OnNavigatedTo is called.
Code Walk-Through: To see how pages are retained in
Page1 Page2 Page3 memory while they’re in the back stack, explore the Garbage-
CollectedSample page included in the accompanying code
Navigate download. It keeps a running tally of pages in memory, and you
(Page1.xaml)
can see it increase as you navigate forward and decrease as you
Navigate navigate back from a page.
(Page2.xaml) That wraps up the first part of our series. Next month, we’ll
focus on advanced navigation topics.
Navigate
(Page3.xaml)
YOCHAY KIRIATY is a senior technical evangelist at Microsoft, focusing on client
technologies such as Windows and Windows Phone. He coauthored the books
GoBack “Introducing Windows 7 for Developers” (Microsoft Press, 2009) and “Learning
Windows Phone Programming” (O’Reilly Media, 2011).
GoBack
J AIME R ODRIGUEZ is a principal evangelist at Microsoft driving adoption
of emerging client technologies such as Silverlight and Windows Phone. You
GoBack can reach him on Twitter: @jaimerodriguez or on blogs.msdn.com/jaimer.
(Exits app)
;<M<CFG<;=FI
List sub
bUnorderedS
SubList2
st = unorderedSubL
S bList.Items
ist. s[1].Su
ubLis
sts.A
AddUnorde
eredSu
edS bLis
bL t();
t() su
ubUnorderedSubList2.Items.Add(“Man
a go”); subUnorrdere
edS
SubList2.I
t2 tem
ms.A
Add(“Banana”);
); Un
Unord
deredS
dS
Su Lis
SubList
s sub
ubUnor
n dere
de dSubList
t();
() subU
Unordered
dSubList3.Items.Add(“Swe
Swee
w t Po
Potato””); Uno
order
d redS
SubList sub
bUnor
Uno dere
er dSub
dSubList
List4
4 = unorrderedSubList2.It
2 ems[1].S
].SubLists.AddUno
orde
ered
dSub
bList(
s ); subUn
ubU orderedSubLi
ubList
b st4.
s Ite
ems.Ad
A d(“S
Ad “Strin
ing Be
ean”)
an” ; subUno
U rde
Add(“Kid
dney Bean
ean”); x += 279; pag
a e.Eleme
ements.Ad
dd(u
d nordere
edLisst); unorderedList
Lis = unord
nordered
ere List.GetOver
e FlowList(x + 5, y + 20);
) Add
A CaptionAndRec
ctan
ngle(p
page
ag .Eleme
ents, “Unor
Unordere
dere
r d List Page
e Elem
ment Ove
ve flow:
ver flo ”, x, y, 225
oid
d Add
dTextField(Group pageElemen
dTextF me ts,, flo
float x,, flo
oat y)) { Tex
xtField txtt = new TextFi
xtF eld(“txt
“t fna
fname”, x + 20, y + 40, 120, 20); txt.Defaul
u tValue = “This is a Scrrollab
ble
e TextF
Field
d”; txt.Borde
derCol
rCol
C o or = Rgb
RgbCColo
or.B
r.Black; txt
xt ackgro
xt.BackgroundC
un o
d(txt); T
d( TextField
ex txt1 = new TextFi
Field(
ld “tx
xtf1na
f1 me”,
me” x + 175, y + 40, 120, 20); txtt1.Def
De ault
u Valu
alue = “TextField”; txt1.Password = true; txt1.MaxLength = 9; txtt1.Bo
ord
derColor = RgbCollor.Black;
or.B
B txt1.B
1.Backg
ckgroun
ou dCol
olor
or = Rgb
R Colo
Colorr.Al
Al
e ies(); pieSeries.DataLabel = da
er da;
a; plo
p tAre
Area
a.Series
rie .Add(pieS
Series
s); pieSeries.Eleme
lementss.Add(
Add(27,
27, “Website A”); pieSeries.Elements.Add
d (19, “Website B”)); pieSerries
es.Element
men s.Add(21
d(21, “W
Web
ebsi
s te
e C”);
); pieS
p eries.El
Elemen
ements[0
me ts[0
s[0].Co
s[0 ].C lor
or = a
ess.Elements[2].Color = aut
utogra
og dien
dientt3;”RgbC
RgbColo
or.Alice
eBlue; txt2.Too
.ToolTip = “Multilin
ne”; page
pageEl
Elements.Add(txt2); AddCaptionAndRectangle(pageEleme
mennts, “Tex
xtFi
Field Form
orm Pag
Pagee Elemen
Elemen
nt:”,
:”, x, yy,, 504
04, 85);
5) } priva
ate
e void
oid AddC
dComb
omb
@EKL@K@M<LJ<
C
Comb oBox(“cm
mbnam
bna e”, x + 51, y + 40, 150,
15 20); cb.B
BorderColo
or = RgbColor.Blac
Black; cb.Ba
b.Back
ckgroundColor = RgbColor.AliceBlue; cb.Font = Font.Helve
elvetica
a; cb
b.Fon
Fo tSiz
Sizze = 12; cb.I
cb.Items
temss A (“Item
tems.Add e 1”);
em ); cb.
cb.Items
tems.Add
.Add(“It
Ad (“It
( Item
em 2”); cb
d table””);
di ”) cb.Item
ms[
s[“
[“Edita
able”].Select
cted
ed = true;; c
cb.Editable = tru
ue; cb.ToolTip = “Edi
“Ed tabl
ab e Co
C mbo Box”; pageElements.Add(cb); ComboBox cb1 = new
ew Combo
omb
b Box(
B x(“cmb
mb1nam
me”, x + 303,
303, y + 40, 150, 20);
20); cb1.B
cb1 Borde
rder
derColor = R
= Font.H
Helvetic
ca; cb
cb1.FontS
nt ize = 12
2; cb1.Itemss.A
Add(“IItem 1”); cb1.Ittems.Add(“It
“Item
em 2”);
”) cb1.
cb1.It
Items.Add(“Item 3”); cb1.Items.Add(“Item 4”); cb1.Itemss.A
Add
d(“No
on-Edi
ditab
table
e”);
); c
cb1.Items[“
[“Non-
“Non-Edit
Editable
able”].S
”].Seelected = true; cb1.
1 Edita
nts.Ad
nts d(cb
(cb1); Converter.Co
C nvert(“http://www.go
goog
ogle.c
com”, “Outputt.pdf”);Convert
ve er.C
er.Conve
onvert(GetDocPath(“DocumentA.rtf”), “Output.pdf”);System.Dia
iagno
ostics
css.Pro
P ocess
ess.S
s Start(“Outp
tput.p
ut.pdf”)
pdf”);; AsyncC
As ncConverter
rt aCo
Co
onverte
nve er = new A
err(aCo
(aC nverrter_Converted); aConverter.ConversionErro
or += new Con
nversionErrorEv
ventH
tHandler(aConverter_ConversionError); aConverter.Convert(@”C:\t
C:\ em
mp\Docum
mp mentA.rtf”, @”C:\tem
ment em
mp\Ou
p\Output
tputA.pd
A.pdf”);
f”);
) aConver
v rter.
ter.Co
onvert(@”C
ve t(@”C:\temp\DocumentC.rtf”, @”C:\temp\OutputC
ver C.pdf”)); aCo
onve
erter.Convert(
e “h http://
p://www.yahoo.com”, @”C:\Temp\yahoo.pdf”); ConversionOptions
ion op
option
ns = new Conversio
ns sionOpt
nOpttions
ions(720
(720,, 720,
72 72, true); ce
eTe.D
Te. ynamicPDF
te \\o
temp output.pdf”, options); ceTe.DynamicPDF.Conve
ersion.Con
nvertter.Convert(“C:\\\te
emp\\Document2.docx”, “C:\\temp\\output.pdf”, options); string
g sam
ampl
mp eHtm
mp H mll = “<ht
h ml><
ml><body
body><p>
><p>
p This is a very simpl
m e HTML
ML strring includ
<t le border=\”1\”>
<tab 1 <tr><td>100</td><td>200</td>”” + “<ttd>3
300<
</td></tr><tr><
<td>
>400</td><td>500</td><td>600</t
< d></tr></table><
></bod
/body><
y></
</h
</
/htm
ht >”;Conve
html o version.Co
n.Co
C nver
nverter.
ter.C
ConvvertHtmlString(sa
ample
mpleHtmll, “C:\\
“C \temp\
emp\\Sam
\Sam
erName
er e”, Path.Comb
o ine(GetPath(), “LetterPortrait.pdff”)); prrintJo
ob.D
DocumentName
e = “Lett
Letter
e Portrait”; if (printJob.P
ob. rinter.Color)
r pri tJob.PrintOp
prin P ntO
n tions.Co
s. lor
o = true;
true; if (prin
(prin
ri tJob
tJo .Printer.Col
C late) printJob.P
b.P
.P
PrintOpti
Opti
p ons.
ons Co
on ollat = tru
ollate
;peXd`ZG;=Ç:fdgi\_\ej`m\G;=Jfclk`fej]fi%E<K;\m\cfg\ij
Z\K\ Jf]knXi\Ëj ;peXd`ZG;= gif[lZkj gifm`[\ i\Xc$k`d\ G;= ^\e\iXk`fe# dXe`glcXk`fe# Zfem\ij`fe#
gi`ek`e^#m`\n`e^#Xe[dlZ_dfi\%Gifm`[`e^k_\Y\jkf]Yfk_nfic[j#k_\fYa\Zkdf[\cjXi\\oki\d\cp
Õ\o`Yc\ Ylk jk`cc jlggcp k_\ i`Z_ ]\Xkli\j pfl e\\[ Xj X [\m\cfg\i% I\c`XYc\ Xe[ \]ÔZ`\ek# k_\ _`^_$
g\i]fidXeZ\ jf]knXi\ `j \Xjp kf c\Xie Xe[ lj\% @] pfl [f \eZflek\i X hl\jk`fe n`k_ Xep f] fli
NNN%;PE8D@:G;=%:FD
Zfdgfe\ekj#j`dgcpZfekXZkZ\K\Jf]knXi\Ëji\X[`cpXmX`cXYc\#`e[ljkip$c\X[`e^jlggfikk\Xd%
KIPFLIG;=JFCLK@FEJ=I<<KF;8P
nnn%;peXd`ZG;=%Zfd&\mXcfiZXcc/''%-/(%,''/s"(+('%..)%/-)'
Diffusion Testing
86 msdn magazine
Figure 2 Generating a New Test Case one that isn’t diffusion testing, is when you’re testing a function
static string CreateDiffusedTestCase(string existingTestCase)
where switching the order of input values doesn’t change the return
{ value, such as with Sum(x,y).
// Assumes input format is CaseID:N:K:Expected
string[] tokens = existingTestCase.Split(':');
Mathematical functions are the most common type of component
under test that can benefit from diffusion testing, because such func-
string oldTestCase = tokens[0];
int oldN = int.Parse(tokens[1]); tions most often are recurrent, monotonic or symmetric—but you
int oldK = int.Parse(tokens[2]); should be alert to other situations, too. Mathematical functions that
long oldExpected = long.Parse(tokens[3]);
involve recurrence relations are especially well-suited for diffusion
string newTestCase = oldTestCase + "-diffused"; testing because you can often generate multiple new test cases from
int newN = oldN + 1;
int newK = oldK; an existing test case. In the demo in Figure 1, test case 001 with n =
long newExpected = (oldExpected * (oldN + 1)) / (oldN - oldK + 1); 8, k = 3 and expected = 56 generated a new diffused test case with
return newTestCase + ":" + newN + ":" + newK + ":" + newExpected; n = 9, k = 3 and expected = 84. This new test case could be used to
} generate another test case with n = 10, k = 3 and expected = 120, and
if that test case passed, it could be used to generate yet another new
is shown in Figure 2. The entire program that generated the output test case, and so on.
shown in Figure 1 is available at code.msdn.microsoft.com/mag201103TestRun.
testing techniques.
for what it is—simply a label to describe a software-testing technique,
but one that can be a useful addition to your technical toolkit.
The examples I’ve presented illustrate the three most common— DR. JAMES MCCAFFREY works for Volt Information Sciences Inc., where he man-
but by no means the only—scenarios where diffusion testing is ages technical training for software engineers working at the Microsoft Redmond,
applicable. The first scenario is where you’re testing a mathematical Wash., campus. He’s worked on several Microsoft products, including Internet
Explorer and MSN Search. Dr. McCaffrey is the author of “.NET Test Automation
function that can be defined as a recurrence relationship. The second Recipes” (Apress, 2006), and can be reached at jammc@microsoft.com.
scenario is where you’re testing a function that has some monotonic
relationship. And the third scenario is where you’re testing a function THANKS to the following technical experts for reviewing this article:
that has some symmetric relationship. A related form of testing, but Bj Rollison and Alan Page
THE REAL-WORLD
TRAINING YOU NEED.
If you’re looking for hard-hitting .NET
development training, look no further
than Visual Studio Live! Las Vegas.
Our goal? To arm you with the knowledge
to build better applications.
You'll learn tips, tricks and fixes from .NET pros like Billy Hollis,
Rockford Lhotka, Andrew Brust, Deborah Kurata and Dave Mendlen,
Senior Director, Developer Platform and Tools at Microsoft.
DOWNLOAD
THE AGENDA
REGISTER BY MARCH 23
NOW! SAVE $200!
USE CODE MARAD
SUPPORTED BY:
PRODUCED BY:
WWW.VSLIVE.COM/LV
Untitled-6 3 2/2/11 2:01 PM
UI FRONTIERS CHARLES PETZOLD
As someone who spends much of his professional life observing the us a “sneak peek” at enhancements to the frameworks that might be
evolution of APIs, I’ve been quite entertained by that little corner incorporated in future releases. Full source code is an extra bonus.
of the API universe occupied by multi-touch. I’m not sure I’d even Windows Phone 7 now also benefits from this custom. The Silverlight
want to count the number of different multi-touch APIs spread out for Windows Phone Toolkit (available at silverlight.codeplex.com) contains
over Windows Presentation Foundation (WPF), Microsoft Surface, DatePicker, TimePicker and ToggleSwitch controls already familiar
Silverlight, XNA and Windows Phone, but what’s most evident is to users of Windows Phone 7; a WrapPanel (handy for dealing with
that a “unified theory” of multi-touch is still elusive. phone orientation changes); and multi-touch gesture support.
Of course, this plethora of touch APIs shouldn’t be surprising for
by multi-touch.
even if we’re touching the glossy surface of a video display.
For the application programmer, Windows Phone 7 defines
four—yes, four—different touch interfaces.
Silverlight applications written for Windows Phone 7 have This new Silverlight gesture support in the toolkit is intended to
the option of obtaining low-level touch input through the static be similar to the XNA TouchPanel.ReadGesture method, except
Touch.FrameReported event, or higher-level input through the it’s delivered through routed events rather than polling.
various Manipulation routed events. These Manipulation events How similar is it? Much more so than I expected! Looking at
are mostly a subset of similar events in WPF, but they’re different the source code, I was quite surprised to discover that these new
enough to cause major headaches. Silverlight gesture events were entirely derived from a call to the
XNA applications for Windows Phone 7 use the static TouchPanel XNA TouchPanel.ReadGesture method. I wouldn’t have thought
class to obtain touch input, but that single class actually incorpo- that a Silverlight application on Windows Phone was allowed to
rates two touch interfaces: The GetState method obtains low-level call this XNA method, but there it is.
finger activity, and the ReadGesture method obtains higher-level Although the Silverlight and XNA gestures are fairly similar, the
gestures. The gestures supported by the ReadGesture method are properties associated with the gestures are not. The XNA properties
not stylus-like gestures such as checkmarks and circles. They’re use vectors, for example, and because Silverlight doesn’t include a
much simpler gestures described by names such as Tap, Drag and Vector structure (an omission I feel is ridiculous), the properties
Pinch. In keeping with XNA architecture, touch input is polled by had to be redefined for Silverlight in certain simple ways.
the application rather than being delivered through events. As I’ve been working with these gesture events, they’ve come to
be my favorite multi-touch API for Silverlight for Windows Phone.
Gestures Come to Silverlight I’ve found them to be comprehensive for much of what I need to
I naturally assumed that Silverlight for Windows Phone 7 already do and also fairly easy to use.
had a sufficient number of multi-touch APIs, so I was quite surprised Let me demonstrate by giving these gestures actual work to do.
to see a third one added to the mix—albeit in a toolkit that came
out a little too late for me to describe in my book, “Programming Gesture Service and Listener
Windows Phone 7” (Microsoft Press, 2010). All the source code for this column is in a downloadable Visual Studio
As you probably know, various releases of WPF and Silverlight solution named GestureDemos that contains three projects. You’ll
over the past several years have been supplemented by toolkits
released through CodePlex. These toolkits allow Microsoft to get new Code download available at code.msdn.microsoft.com/mag201103UIFrontiers.
classes to developers outside of the usual ship cycle and often give
92 msdn magazine
need to have the Windows Phone 7 development tools installed, of Figure 1 The Image Element in ScaleAndRotate
course, and also the Silverlight for Windows Phone Toolkit. <Image Name="image"
After installing the toolkit, you can use it in your own Windows Source="PetzoldTattoo.jpg"
Stretch="None"
Phone projects by adding a reference to the Microsoft.Phone.Con- HorizontalAlignment="Left"
trols.Toolkit assembly. In the Add Reference dialog box, it should VerticalAlignment="Top">
<Image.RenderTransform>
be listed under the .NET tab. <TransformGroup>
In a XAML file, you’ll then need an XML namespace declaration <MatrixTransform x:Name="previousTransform" />
like this one (but all on one line): <TransformGroup x:Name="currentTransform">
xmlns:toolkit=
<ScaleTransform x:Name="scaleTransform" />
"clr-namespace:Microsoft.Phone.Controls;
<RotateTransform x:Name="rotateTransform" />
assembly=Microsoft.Phone.Controls.Toolkit"
<TranslateTransform x:Name="translateTransform" />
Here are the 12 available gesture events, roughly in the order that </TransformGroup>
</TransformGroup>
I’ll discuss them (the events that I’ve grouped on a single line are </Image.RenderTransform>
related and occur in a sequence): </Image>
GestureBegin, GestureCompleted
Tap
DoubleTap fingers have left the screen. These events may be handy for initial-
Hold ization or cleanup, but you’ll generally be more focused on gesture
DragStarted, DragDelta, DragCompleted
Flick events that occur between these two events.
PinchStarted, PinchDelta, PinchCompleted I’m not going to spend much time on the simpler gestures. A
Suppose you want to handle Tap and Hold events that occur on Tap occurs when a finger touches the screen and then lifts up
a Grid or any child of the Grid. You can specify that in the XAML within about 1.1 seconds, without moving too far from the original
file like so: position. If two taps are close in succession, the second one comes
<Grid ... > through as a DoubleTap. A Hold occurs when a finger is pressed
<toolkit:GestureService.GestureListener>
<toolkit:GestureListener on the screen and remains in roughly the same spot for about
Tap="OnGestureListenerTap" 1.1 seconds. The Hold event is generated at the end of this time
Hold="OnGestureListenerHold" />
</toolkit:GestureService.GestureListener> without waiting for the finger to lift.
...
well-known ways.
vides the current coordinates of that finger relative to any element.
The gesture events are routed, which means that they can travel
up the visual tree and be handled for any element that has a
GestureListener installed. As usual, an event handler can set the Because the finger has already begun moving when the Drag-
Handled property of GestureEventArgs to true to prevent an event Started event is fired, the DragStartedEventArgs object can include
from travelling further up the visual tree. However, this only affects a Direction property of type Orientation (Horizontal or Vertical).
other elements using these gesture events. Setting Handled to true The DragDeltaEventArgs object accompanying the DragDelta
does not prevent elements higher in the visual tree from obtaining event includes more information: HorizontalChange and Vertical-
touch input through other interfaces. Change properties that are convenient for adding to the X and
The GestureBegin event indicates that a finger has touched a Y properties of a TranslateTransform, or the Canvas.Left and
previously fingerless screen; GestureCompleted signals when all Canvas.Top attached properties.
msdnmagazine.com March 2011 93
The Flick event occurs when a finger leaves the screen as it’s to entirely reconstruct the positions of the two fingers, so you can
still moving, suggesting that the user wants inertia to occur. The always go back to first principles if you need to.
event arguments include an Angle (measured clockwise from During a Pinch sequence, the current location of one finger—let’s
the positive X axis) and HorizontalVelocity and VerticalVelocity call it the primary finger—is always available with the GetPosition
values, both in pixels per second. method. For this discussion, call that return value pt1. For the
The Flick event can occur in isolation; or it can occur between PinchStarted event, the PinchStartedGestureEventArgs class has
DragStarted and DragCompleted events without any DragDelta two additional properties named Distance and Angle indicating
events; or it might follow a series of DragDelta events before the location of the second finger relative to the first. You can easily
DragCompleted. Generally you’ll want to handle Drag events and calculate that actual location using the following statement:
Flick events in conjunction, almost as if the Flick is a continuation Point pt2 = new Point(pt1.X + args.Distance * Cos(args.Angle),
pt1.Y + args.Distance * Sin(args.Angle));
of the Drag. However, you’ll need to add your own inertia logic.
The Angle property is in degrees, so you’ll need Cos and Sin
methods to convert to radians before calling Math.Cos and
Although the Silverlight and XNA Math.Sin. Before the PinchStarted handler has completed, you’ll
also want to save the Distance and Angle properties in fields,
gestures are fairly similar, the perhaps named pinchStartDistance and pinchStartAngle.
The PinchDelta event is accompanied by a PinchGestureEvent-
properties associated with the Args object. Once again, the GetPosition method gives you the
location of the primary finger, which has perhaps moved from
gestures are not. its original location. For the second finger, the event arguments
provide DistanceRatio and TotalAngleDelta properties.
This is demonstrated in the DragAndFlick project. The display The DistanceRatio is the ratio of the current distance between
contains an ellipse that the user simply drags around with a finger. If the fingers to the original distance, which means you can calculate
the finger leaves the screen with a flicking motion, then a Flick event the current distance like so:
double distance = args.DistanceRatio * pinchStartDistance;
occurs and the Flick handler saves some information and installs a
The TotalAngleDelta is a difference between the current angle
handler for the CompositionTarget.Rendering event. This event—
between the fingers and the original angle. You can calculate the
which occurs in synchronization with the video display refresh—keeps
current angle like this:
the ellipse moving while applying a deceleration to the velocity. double angle = args.TotalAngleDelta + pinchStartAngle;
Bouncing off the sides is handled a bit unusually: The program Now you can calculate the location of the second finger as before:
maintains a position as if the ellipse simply keeps moving in the Point pt2 = new Point(pt1.X + distance * Cos(angle),
same direction until it stops; that position is folded into the area pt1.Y + distance * Sin(angle));
in which it can bounce. You don’t need to save any additional information to fields during
PinchDelta handling to process further PinchDelta events.
Pinch Me, I Must Be Dreaming
For the application programmer,
The Pinch sequence occurs when two fingers are touching the
screen; it’s generally interpreted to expand or contract an on-screen
four—yes, four—different
of the most treacherous areas of multi-touch processing, and it’s
not unusual to see higher-level interfaces fail at providing adequate
touch interfaces.
information. Most notoriously, the Windows Phone 7 Manipulation-
Delta event is particularly tricky to use.
When handling gestures, Drag sequences and Pinch sequences
are mutually exclusive. They don’t overlap but they can occur back The TwoFingerTracking project demonstrates this logic by displaying
to back. For example, press a finger to the screen and drag it. That blue and green ellipses that track one or two fingers around the screen.
generates a DragStarted and multiple DragDelta events. Now press
a second finger to the screen. You’ll get a DragCompleted to com- Scale and Rotate
plete the Drag sequence followed by a PinchStarted and multiple The PinchDelta event also provides sufficient information to per-
PinchDelta events. Now lift the second finger while the first finger form scaling and rotation on objects. I had to supply my own matrix
keeps moving. That’s a PinchCompleted to complete the Pinch multiplication method, but that was about the extent of the hassles.
sequence, followed by DragStarted and DragDelta. Depending To demonstrate, the ScaleAndRotate project implements what is
on the number of fingers touching the screen, you’re basically now a “traditional” type of demonstration that lets you drag, scale
alternating between Drag sequences and Pinch sequences. and optionally rotate a photograph. To perform these transforms, I
One helpful characteristic of this Pinch gesture is that it doesn’t defined the Image element with a double-barreled RenderTransform
discard information. You can use properties of the event arguments as shown in Figure 1.
94 msdn magazine UI Frontiers
Figure 2 The ScaleAndRotate Code
public partial class MainPage : PhoneApplicationPage void OnGestureListenerPinchDelta(object sender, PinchGestureEventArgs args)
{ {
bool isDragging; if (isPinching)
bool isPinching; {
Point ptPinchPositionStart; // Set scaling
scaleTransform.ScaleX = args.DistanceRatio;
public MainPage() scaleTransform.ScaleY = args.DistanceRatio;
{
InitializeComponent(); // Optionally set rotation
} if (allowRotateCheckBox.IsChecked.Value)
rotateTransform.Angle = args.TotalAngleDelta;
void OnGestureListenerDragStarted(object sender, DragStartedGestureEventArgs args)
{ // Set translation
isDragging = args.OriginalSource == image; Point ptPinchPosition = args.GetPosition(this);
} translateTransform.X = ptPinchPosition.X - ptPinchPositionStart.X;
translateTransform.Y = ptPinchPosition.Y - ptPinchPositionStart.Y;
void OnGestureListenerDragDelta(object sender, DragDeltaGestureEventArgs args) }
{ }
if (isDragging)
{ void OnGestureListenerPinchCompleted(object sender, PinchGestureEventArgs args)
translateTransform.X += args.HorizontalChange; {
translateTransform.Y += args.VerticalChange; if (isPinching)
} {
} TransferTransforms();
isPinching = false;
void OnGestureListenerDragCompleted(object sender, }
DragCompletedGestureEventArgs args) }
{
if (isDragging) void TransferTransforms()
{ {
TransferTransforms(); previousTransform.Matrix = Multiply(previousTransform.Matrix,
isDragging = false; currentTransform.Value);
}
} // Set current transforms to default values
scaleTransform.ScaleX = scaleTransform.ScaleY = 1;
void OnGestureListenerPinchStarted(object sender, scaleTransform.CenterX = scaleTransform.CenterY = 0;
PinchStartedGestureEventArgs args)
{ rotateTransform.Angle = 0;
isPinching = args.OriginalSource == image; rotateTransform.CenterX = rotateTransform.CenterY = 0;
When a Drag or Pinch operation is in progress, the three trans- change for the duration of the Pinch sequence. During PinchDelta
forms in the nested TransformGroup are manipulated to move events, the DistanceRatio and TotalAngleDelta properties provide
the picture around the screen, scale it and rotate it. When a Drag- scaling and rotation information relative to that center. Any change
Completed or PinchCompleted event occurs, the Matrix in the in movement of the primary finger (which must be detected with a
MatrixTransform named previousTransform is multiplied by saved field) then becomes an overall translation factor.
the composite transform available as the Value property of the That’s certainly the simplest pinch code I’ve ever written, and
TransformGroup. The three transforms in this TransformGroup that fact is perhaps the best endorsement I can provide for this
are then set back to their default values. new gesture interface.
Scaling and rotation are always relative to a center point, which Perhaps a unified theory of multi-touch isn’t far off after all.
is the point that remains in the same location when the transform
occurs. A photograph scaled or rotated relative to its upper-left CHARLES PETZOLD is a longtime contributing editor to MSDN Magazine. His
corner ends up in a different location than a photograph scaled or new book, “Programming Windows Phone 7” (Microsoft Press, 2010), is avail-
rotated relative to its lower-right corner. able as a free download at bit.ly/cpebookpdf.
The ScaleAndRotate code is shown in Figure 2. I use the primary
finger as the scaling and rotation center; these center points are set THANKS to the following technical expert for reviewing this article:
on the transforms during PinchStarted handling and they don’t Richard Bailey
msdnmagazine.com March 2011 95
DON’T GET ME STARTED DAVID PLATT