MDN_1403DS
-
Upload
israel-lerma-hernandez -
Category
Documents
-
view
225 -
download
0
Transcript of MDN_1403DS
-
8/21/2019 MDN_1403DS
1/108
magazine
THE MICROSOFT JOURNAL FOR DEVELOPERS MARCH 2014 VOL 29 NO 3
AsynchronousProgramming................18,
http://www.devexpress.com/dashboard -
8/21/2019 MDN_1403DS
2/108
http://www.devexpress.com/superhero -
8/21/2019 MDN_1403DS
3/108
magazine
THE MICROSOFT JOURNAL FOR DEVELOPERS MARCH 2014 VOL 29 NO 3
Patterns for AsynchronousMVVM Applications: Data BindingStephen Cleary. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
Asynchronous TCP Socketsas an Alternative to WCFJames McCaffrey . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
A .NET Developer Primer forSingle-Page ApplicationsLong Le . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
Building a Netduino-BasedHID Sensor for WinRTDonn Morse. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
COLUMNSCUTTING EDGE
A First Look at ASP.NET IdentityDino Esposito, page 6
WINDOWS AZURE INSIDER
The Windows Azure Service Busand the Internet of Things, Part Bruno Terkaly andRicardo Villalobos, page 12
THE WORKINGPROGRAMMER
Getting Started with Oak:Data Validation andWrapping UpTed Neward, page 62
MODERN APPS
A Look at the Hub Project andControl in Windows Store AppsRachel Appel, page 66
DIRECTX FACTOR
Triangles and TessellationCharles Petzold, page 74
DONT GET ME STARTED
The Peasants Are Revolting!David Platt, page 80
AsynchronousProgramming................18,
-
8/21/2019 MDN_1403DS
4/108
http://www.ontimenow.com/msdn -
8/21/2019 MDN_1403DS
5/108
http://www.ontimenow.com/msdn -
8/21/2019 MDN_1403DS
6/108
"lightning fast" Redmond Magazine
"covers all data sources" eWeek
"results in less than a second"InfoWorld
hundreds more reviews and developercase studies at www.dtsearch.com
The Smart Choice for Text Retrievalsince 1991
www.dtSearch.com 1-800-IT-FINDS
Instantly SearchTerabytes of Text
Ask about fully-functional evaluations
25+ fielded and full-text search types
dtSearchs own document filterssupport Office, PDF, HTML, XML, ZIP,emails (with nested attachments), andmany other file types
Supports databases as well as staticand dynamic websites
Highlights hitsin all of the above
APIs for .NET, Java, C++, SQL, etc.64-bit and 32-bit; Win and Linux
dtSearch products:Desktop with Spider Web with Spider
Network with Spider Engine for Win &.NETPublish(portable media) Engine for Linux
Document filters also available for separatelicensing
Printed in the USA
magazineMARCH 2014 VOLUME29NUMBER3
MOHAMMAD AL-SABTEditorial Director/[email protected]
KENT SHARKEYSite Manager
MICHAEL DESMONDEditor in Chief/[email protected]
DAVID RAMELTechnical Editor
SHARON TERDEMANFeatures Editor
WENDY HERNANDEZGroup Managing Editor
SCOTT SHULTZCreative Director
JOSHUA GOULDArt Director
SENIOR CONTRIBUTING EDITORDr. James McCaffreyCONTRIBUTING EDITORSRachel Appel, Dino Esposito, Kenny Kerr,Julie Lerman, Ted Neward, Charles Petzold, David S. Platt,Bruno Terkaly, Ricardo Villalobos
Henry AllainPresident, Redmond Media Group
Michele ImgrundSr. Director of Marketing & Audience EngagementTracy CookDirector of Online Marketing
Irene FincherAudience Development Manager
ADVERTISING SALES: 818-674-3416/[email protected]
Dan LaBiancaVice President, Group PublisherChris KourtoglouRegional Sales ManagerDanna VedderRegional Sales Manager/Microsoft Account Manager
David SeymourDirector, Print & Online ProductionSerena BarnesProduction Coordinator/[email protected]
Neal VitalePresident & Chief Executive Ofcer
Richard VitaleSenior Vice President & Chief Financial OfcerMichael J. ValentiExecutive Vice President
Christopher M. CoatesVice President, Finance & AdministrationErik A. LindgrenVice President, Information Technology & Application Development
David F. MyersVice President, Event Operations
Jeffrey S. KleinChairman of the Board
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 atadditional mailing ofces. 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 [email protected] orcall (847) 763-9560.POSTMASTER:Send address changes to MSDN Magazine, P.O. Box 2166, Skokie, IL 60076. CanadaPublications Mail Agreement No: 40612608. Return Undeliverable Canadian Addresses to CirculationDept. 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. Mailrequests to Permissions Editor, c/o MSDN Magazine, 4 Venture, Suite 150, 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 informationcontained herein is the readers 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. Technicalinaccuracies may result from printing errors and/or new developments in the industry.
Corporate Address:1105 Media, Inc., 9201 Oakdale Ave., Ste 101, Chatsworth, CA 91311,www.1105media.com
Media Kits:Direct your Media Kit requests to Matt Morollo, VP Publishing, 508-532-1418 (phone),508-875-6622 (fax), [email protected]
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: [email protected], www.magreprints.com/QuickQuote.asp
List Rental:This publications subscriber list, as well as other lists from 1105 Media, Inc., is availablefor rental. For more information, please contact our list manager, Jane Long, Merit Direct. Phone: 913-685-1301; E-mail:[email protected]; Web: www.meritdirect.com/1105
All customer service inquiries should be sent to [email protected] orcall 847-763-9560.
http://www.dtsearch.com/http://www.dtsearch.com/http://www.dtsearch.com/http://www.dtsearch.com/http://www.dtsearch.com/http://www.dtsearch.com/http://www.dtsearch.com/http://www.dtsearch.com/http://www.dtsearch.com/http://www.dtsearch.com/http://www.dtsearch.com/http://www.dtsearch.com/http://www.dtsearch.com/http://www.dtsearch.com/http://www.dtsearch.com/http://www.dtsearch.com/http://www.dtsearch.com/http://www.dtsearch.com/http://www.dtsearch.com/http://www.dtsearch.com/http://www.dtsearch.com/http://www.dtsearch.com/http://www.dtsearch.com/http://www.dtsearch.com/http://www.dtsearch.com/http://www.dtsearch.com/http://www.dtsearch.com/http://www.dtsearch.com/http://www.dtsearch.com/http://www.dtsearch.com/http://www.dtsearch.com/http://www.dtsearch.com/http://www.dtsearch.com/http://www.dtsearch.com/http://www.dtsearch.com/http://www.dtsearch.com/http://www.dtsearch.com/http://www.dtsearch.com/http://www.dtsearch.com/http://www.dtsearch.com/http://www.dtsearch.com/http://www.dtsearch.com/http://www.dtsearch.com/http://www.dtsearch.com/http://www.dtsearch.com/mailto:[email protected]:[email protected]:818-674-3416/[email protected]:[email protected]:[email protected]:[email protected]://www.1105media.com/mailto:[email protected]:[email protected]://www.magreprints.com/mailto:[email protected]://www.magreprints.com/mailto:[email protected]://www.meritdirect.com/1105mailto:[email protected]:[email protected]://www.meritdirect.com/1105mailto:[email protected]://www.magreprints.com/mailto:[email protected]:[email protected]://www.1105media.com/mailto:[email protected]:[email protected]:818-674-3416/[email protected]:[email protected]:[email protected]://www.dtsearch.com/ -
8/21/2019 MDN_1403DS
7/108
http://www.leadtools.com/ -
8/21/2019 MDN_1403DS
8/108
msdn magazine4
Dont Get Me Started columnist David Platt this month divesinto the revolt at Avon over the companys attempt to deploy anSAP-based order entry and customer management system. Ourback-page columnist takes his cues from many a muse, be they Nobel-winning physicists or cartoon characters from the funny pages. Andin that last regard, he and I share common inspiration.
When Bill Wattersons brilliant Calvin and Hobbes comic strip
exploded onto newspaper pages in , it was an unexpectedwell spring o insight and wisdom. As a parent, Ive marveled atWattersons ability to capture the simple genius o a boy at play. Andas editor in chie oMSDN Magazine, Ive ound that Wattersonsincorrigible -year-old, Calvin, and his loyal tiger, Hobbes, offerreal lessons or working developers. Here are just a ew.
Test, Test, Test!Te Duplicator story arc is one of my favorites inthe -year run o the comic, but its a cautionary tale or developers.Calvin invented a box that creates copies o himsel, who he hopedwould do all his chores and school work. But Calvin never testedhis Duplicator, and he quickly aced a squad o ill-behaved dupes. ICalvin had designed a test to determine the actual behavior o the
dupes his invention created, he might have saved himself a lot of work.Remediate: Calvin later developed
an add-on or his Duplicator, called theEthicator, which let the operator set eachdupes personality to either Good or Evil.A simple patch saved what would other-wise have been a costly project ailure, asCalvin created a compliant, good-aligneddupe to do his chores.
Fail Gracefully:Alas, the good Calvindupe tried to befriend Calvins nemesis Susie Derkins. I don't mindif he cleans my room and gets me good grades, Calvin griped, but
when he starts talking to girls thats going too darn ar. Te unpre-dicted behavior led to an angry confrontation between Calvin andhis dupe, who suddenly cried Oops! Ive had an evil thought! and
vanished in a puff of smoke. An exception-handling routine couldhave preserved the investment in the duplicate Calvin.
Value ExtensibilityTen there was the ransmogrier, whichcould turn anyone into one of four target animals: eel, baboon, giantbug or dinosaur. Calvin showed great awareness allowing supportor additional targets, including an extensible UI to handle them.Te ransmogrier would later support worms, elephants, tigersand giant slugs. I wonder i he used XML?
Leverage the platformBoth the Duplicator and ransmogrier
as well as later Calvin inventions the Cerebral Enhance-O-ron andthe ime Machinewere built on a common, corrugated cardboardbox platform and permanent marker UI. Simple geometries, famil-iar materials and streamlined interfaces dened all four inventions.
Dont Skimp on SecurityWhen Calvinand Hobbes created their exclusive club,Get Rid O Slimy girlS (G.R.O.S.S), theysecured entry to the club treehouse with along, multi-verse password about tigers,which ended with the line igers aregreat! Teyre the toast o the town. Liesalways better when a tigers around! Tat
inal stanza alone is a -bit password,and I havent even described the dancing component. But Calvinstruggled to remember the verse, illuminating the deep challengeo balancing usability and security.
Mind the org chart:G.R.O.S.S. offered a nal, valuable lessonthedanger posed by vague, shifing or tangled lines o authority. Calvinmay have been Dictator or Lie o G.R.O.S.S., but that didnt stopFirst iger Hobbes rom trying to usurp his authority. Constantmanagement reorgs created a volatile environment that producedhijacked meetings, failed initiatives and constant, internecine bicker-ing. G.R.O.S.S. never did mount a successful attack on Susie Derkins.
Make Space for Creativity I Wattersons protagonists have
one message or developers, its this: Dare to dream. Some oCalvins greatest insights occur while careening through the woodsin a toboggan or wagon. ake risks. Make mistakes. And, remem-ber, lifes always better when atigers around.
Everything I Need to KnowI Learned from Calvin and Hobbes
2014 Microsoft Corporation. All rights reserved.
Complying with all applicable copyright laws is the responsibility of the user. Without limiting the rights under copyright, you are not permitted to reproduce, store, or introduce into a retrieval system MSDN Magazineor any part of MSDNMagazine. If you have purchased or have otherwise properly acquired a copy of MSDN Magazinein paper format, you are permitted to physically transfer this paper copy in unmodied form. Otherwise, you are not permitted to transmitcopies of MSDN Magazine(or any part of MSDN Magazine) in any form or by any means without the express written permission of Microsoft Corporation.
A listing of Microsoft Corporation trademarks can be found at microsoft.com/library/toolbar/3.0/trademarks/en-us.mspx. Other trademarks or trade names mentioned herein are the property of their respective owners.
MSDN Magazineis published by 1105 Media, Inc. 1105 Media, Inc. is an independent company not afliated with Microsoft Corporation. Microsoft Corporation is solely responsible for the editorial contents of this magazine. Therecommendations and technical guidelines in MSDN Magazine are based on specic environments and congurations. These recommendations or guidelines may not apply to dissimilar congurations. Microsoft Corporation does not makeany representation or warranty, express or implied, with respect to any code or other information herein and disclaims any liability whatsoever for any use of such code or other information.MSDN Magazine, MSDN, and Microsoft logos areused by 1105 Media, Inc. under license from owner.
Visit us at msdn.microsoft.com/magazine. Questions, comments or suggestions for MSDN Magazine? Send them to the editor: [email protected].
MICHAEL DESMONDEDITORSNOTE
http://msdn.microsoft.com/magazinemailto:[email protected]://msdn.microsoft.com/magazinemailto:[email protected] -
8/21/2019 MDN_1403DS
9/108
http://www.amyuni.com/ -
8/21/2019 MDN_1403DS
10/108
msdn magazine6
Offspring o the One ASP.NE approach to Web development thatcame with Visual Studio 1, the new ASP.NE Identity system is thepreerred way to handle user authentication in ASP.NE applications,whether based on Web Forms or MVC. In this column, Ill reviewthe basics o ASP.NE authentication and explore the new ASP.NEIdentity system rom the perspective o ASP.NE MVC developers.
ASP.NE has long supported two basic types o authentication:Windows authentication and orms authentication. Windowsauthentication is seldom practical or public Web sites becauseits based on Windows accounts and access control list (ACL)tokens. Tus, it requires users to have a Windows account in theapplications domain, and it also assumes clients are connectingrom Windows-equipped machines. he other option is ormsauthentication, a widely adopted approach. Forms authenticationis based on a simple idea. For each access to a protected resource,the application ensures the request includes a valid authentica-tion cookie. I a valid cookie is ound, then the request is served asusual; otherwise, the user is redirected to a login page and asked
to provide credentials. I these credentials are recognized as valid,then the application issues an authentication cookie with a givenexpiration policy. Its simple and it just works.
Implementation o any orms authentication module cant happen
without a distinct module that takes care o collecting user creden-tials and checking them against a database o known users. Writingthis membership subsystem has been one o the key responsibilitieso development teamsbut also one o the most annoying thingsever. Writing a membership system is not hard, per se. It mostlyrequires running a query against some sort o storage system andchecking a user name and password. Tis code is boilerplate andcan grow airly big as you add new authentication eatures such aschanging and recovering passwords, handling a changing numbero online users and so on. In addition, it has to be rewritten nearlyrom scratch i you change the structure o the storage or add moreinormation to the object that describes the user. Back in , with
the release o ASP.NE ., Microsof addressed this problem by
introducing right into the ramework a provider-based architectureand the membership provider. Instead o reinventing the wheelevery time, you could just derive membership rom the built-insystem and override only the unctions you intended to change.
he ASP.NE native membership provider is a standalonecomponent that exposes a contracted interace. he ASP.NEruntime, which orchestrates the authentication process, is awareo the membership interace and can invoke whatever componentis conigured as the membership provider o the application.ASP.NE came with a deault membership provider based on anew given database schema. However, you could easily write yourown membership provider to basically target a different databasetypically, an existing database o users.
Does that sound like a great chunk o architecture? In the begin-ning, nearly everybody thought so. In the long run, though, quitea ew people who repeatedly tried to build a custom membership
provider started complaining about the verbosity o the interace.Actually, the membership provider comes in the orm o an inher-itable base class, MembershipProvider, which includes more than members marked as abstract. Tis means that or any new mem-bership provider you wanted to create, there were at least mem-bers to override. Worse yet, you didnt really need many o themmost o the time. A simpler membership architecture was needed.
Introducing the Simple Membership Providero save you rom the burden o creating a custom membership layercompletely rom scratch, Microsof introduced with Visual Studio1 SP1 another option: the simple membership API. Originally
available in WebMatrix and Web Pages, the simple membership
A First Look at ASP.NET Identity
CUTTINGEDGE DINO ESPOSITO
public class AccountController : Controller{ public UserManager UserManager { get; private set; }
public AccountController(UserManager manager) { UserManager = manager; }
public AccountController() :this(new UserManager(
new UserStore(new ApplicationDbContext()))) { }
...}
Figure 1 Foundation of a Controller Based on ASP.NET Identity
The simple membership API has
become quite a popular way of
managing authentication.
-
8/21/2019 MDN_1403DS
11/108
http://www.devexpress.com/touch -
8/21/2019 MDN_1403DS
12/108
msdn magazine8 Cutting Edge
API has become quite a popular way o managing authentication,especially in ASP.NE MVC. In particular, the Internet applicationtemplate in ASP.NE MVC uses the simple membership API tosupport user management and authentication.
Looking under the hood o the API, it turns out that its just a
wrapper on top o the classic ASP.NE membership API and itsSQL Server-based data stores. Simple membership lets you workwith any data store you have and requires only that you indicatewhich columns in the table serve as the user name and user ID.
he major dierence rom the classic membership API is asignicantly shorter list o parameters or any methods. In addi-tion, you get a lot more reedom as ar as the schema o the mem-bership storage is concerned. As an example of the simplied API,consider what it takes to create a new user:
WebSecurity.CreateUserAndAccount(username, password, new { FirstName = fname, LastName = lname, Email = email });
You do most o the membership chores via the WebSecurity class.In ASP.NE MVC , however, the WebSecurity class expects to work
with an extended membership provider, not a classic membership pro-vider. Te additional capabilities in an extended membership providerare related to dealing with OAuth accounts. As a result, in ASP.NEMVC , you have two parallel routes or membership implemen-tation: classic membership API using the MembershipProviderclass and simple membership API using the ExtendedMember-shipProvider class. Te two APIs are incompatible.
Beore the arrival o Visual Studio 1 and ASP.NE MVC ,ASP.NE already offered quite a ew ways to handle user authen-tication. With orms authentication, you could rely on classicmembership, the simple membership API as dened in Web Pagesand a variety o custom membership systems. Consider the com-
mon position among ASP.NE experts was that complex real-worldapplications require their own membership provider. More ofen
than not, the main reason for having a custom membership systemwas to circumvent structural dierences between t he requireddatabase ormat and the ormat o the existing database o usercredentials, which might have been in use or years.
Clearly, this wasnt a situation that could last forever. Te commu-
nity o developers demanded with loud voices a unied system ormembership thats simple to use, narrowly focused and usable in thesame way from within any avor of ASP.NE. Tis idea weds togetherwell with the One ASP.NE approach pushed by Visual Studio 1.
One Identity FrameworkTe purpose o authentication is getting the identity associated withthe current user. Te identity is retrieved and the provided credentialsare compared to records stored in a database. Subsequently, an iden-tity system such as ASP.NE Identity is based on two primary blocks:the authentication manager and the store manager. In the ASP.NEIdentity ramework, the authentication manager takes the orm o
the UserManager class. Tis class basically provides a faadeor signing users in and out. Te store manager is an instance o theUserStore class. Figure 1shows the skeleton o an ASP.NEMVC account controller class thats based on ASP.NE Identity.
Te controller holds a reerence to the authentication identitymanager, UserManager. Tis instance o UserManager is injectedinto the controller. You can use either an Inversion of Control (IoC)framework or the poor mans alternative, the dependency injection(DI) pattern, which uses two controllers, one o which gets adeault value(see Figure 1).
Te identity store, in turn, is injected into the authenticationidentity manager, where its used to veriy credentials. Te identity
store takes the orm o the UserStore class. his classresults rom the composition o multiple types:public class UserStore :IUserLoginStore,IUserClaimStore,IUserRoleStore,IUserPasswordStore,IUserSecurityStampStore,IUserStore,IDisposable where TUser : IdentityUser
{ }
All interaces implemented by UserStore are bas icrepositories or optional user-related data such as passwords, roles,claims and, o course, user data. Te identity store needs to knowabout the actual data source, though. As shown in Figure 1, the datasource is injected in the UserStore class through the constructor.
Storage of users data is managed through the Entity FrameworkCode First approach. Tis means you dont strictly need to create aphysical database to store your users credentials; you can, instead,dene a User class and have the underlying ramework create themost appropriate database to store such records.
Te ApplicationDbContext class wraps up the Entity Frameworkcontext to save users data. Heres a possible deinition or theApplicationDbContext class:
public class ApplicationDbContext : IdentityDbContext{}
Basically, the database context o ASP.NE Identity handles thepersistence of a given user type. Te user type must implement the
namespace Microsoft.AspNet.Identity.EntityFramework{ public class IdentityUser : IUser { public string Id { get; } public string UserName { get; set; } public string PasswordHash { get; set; } public string SecurityStamp { get; set; } public ICollection Roles { get; private set; } public ICollection Claims { get; private set; } public ICollection Logins { get; private set; }
}}
Figure 2 Definition of the Default User Class in ASP.NET Identity
The Internet application
template in ASP.NET MVC 4 uses
the simple membership API to
support user management
and authentication.
-
8/21/2019 MDN_1403DS
13/108
9March 2014msdnmagazine.com
IUser interface or just inherit from IdentityUser. Figure 2presentsthe source code of the default IdentityUser class.
Heres an example of a realistic custom user class you might wantto use in your applications:
public class ApplicationUser : IdentityUser{ public DateTime Birthdate { get; set; }}
Te use of Entity Framework Code First is a great move here as itmakes the structure of the database a secondary point. You still need
one, but to create it, you can use code based on classes. In addition,you can use Entity Framework Code First migration tools to modifya previously created database as you make changes to the class behindit. (For more information on this, see the Code First Migrationsarticle in the MSDN Data Developer Center at bit.ly/Th92qf.)
Authenticating UsersASP.NE Identity is based on the newest Open Web Interface for.NE (OWIN) authentication middleware. Tis means the typicalsteps of authentication (for example, creating and checking cookies)can be carried out through the abstract OWIN interfaces and notdirectly via ASP.NE/IIS interfaces. Support for OWIN requires
the account controller to have another handy property, like this:private IAuthenticationManager AuthenticationManager{ get { return HttpContext.GetOwinContext().Authentication; }}
The IAuthenticationManager interface is defined in theMicrosoft.Owin.Security namespace. his property is import-ant because it needs to be injected into any operation that involvesauthentication-related steps. Heres a typical login method:
private async Task SignInAsync(ApplicationUser user, bool isPersistent){ var identity = await UserManager.CreateIdentityAsync(user,
DefaultAuthenticationTypes.ApplicationCookie); AuthenticationManager.SignIn(new AuthenticationProperties() {
IsPersistent = isPersistent }, identity);}
Te method SignInAsync checks the specied user name andpassword against the store associated with the authenticationmanager. o register a user and add the user to the membershipdatabase, you use code like this:
var user = new ApplicationUser() { UserName = model.UserName };var result = await UserManager.CreateAsync(user, model.Password);if (result.Succeeded)
{ await SignInAsync(user, isPersistent: false); return RedirectToAction("Index", "Home");}
All in all, ASP.NE Identity provides a unified API for tasksrelated to authentication. For example, it unies the code requiredto authenticate against a proprietary database or a social networkOAuth-based endpoint. Figure 3shows a fragment of the codeyou need to authenticate users against an external login engine.Te code in Figure 3gets called once the OAuth authentication(for example, against Facebook) has been completed successfully.
The Bottom LineAs I see things, ASP.NE Identity is an overdue solution that shouldhave come years ago. Te key issue concerning ASP.NE Identityright now is the development team is trying to come up with aprogramming interface thats generic and testable enough to lastfor a long timeor at least until something newer and better showsup in the industry.
For the foreseeable future, ASP.NE Identity promises to beas good as old-fashioned membership was perceived to be adecade ago. Personally, I like the expressiveness of the API and theattempt to fuse together different forms of authenticationbuilt-inand OAuth-based, for example. Another great plus is the integra-tion with OWIN, which makes it somewhat independent from aspecic runtime such as IIS/ASP.NE.
ASP.NE Identity is bound to Visual Studio 1, but its alsoexpected to have an autonomous life of its own when it comes tofuture builds and releases. Ive just scratched the surface of the newidentity API here. Stay tuned for newer builds and releases!
DINOESPOSITOis the author o Architecting Mobile Solutions or the Enterprise(Microsof Press, ) and the up coming Programming ASP.NET MVC (Microsof Press). A technical evangelist or the .NET and Android platorms at Jet-Brains and requent speaker at industry events worldwide, Esposito shares his visiono sofware at sofwarecents.wordpress.com and on Twitter at twitter.com/despos.
THANKSto the following technical expert for reviewing this article:Pranav Rastogi (Microsof)
ASP.NET Identity is bound toVisual Studio 2013, but its also
expected to have an autonomous
life of its own when it comes to
future builds and releases.
public async Task ExternalLoginCallback( string loginProvider, string returnUrl){ ClaimsIdentity id = await UserManager .Authentication
.GetExternalIdentityAsync(AuthenticationManager);var result = await UserManager
.Authentication .SignInExternalIdentityAsync( AuthenticationManager, id); if (result.Success) return RedirectToLocal(returnUrl); else if (User.Identity.IsAuthenticated) { result = await UserManager .Authentication .LinkExternalIdentityAsync( id, User.Identity.GetUserId()); if (result.Success) return RedirectToLocal(returnUrl); else return View("ExternalLoginFailure");
}}
Figure 3 Finalizing the Authentication Process
through an External Endpoint
http://www.msdnmagazine.com/http://www.bit.ly/Th92qfhttp://www.bit.ly/Th92qfhttp://www.bit.ly/Th92qfhttp://www.wordpress.com/http://www.twitter.com/desposhttp://www.twitter.com/desposhttp://www.wordpress.com/http://www.bit.ly/Th92qfhttp://www.msdnmagazine.com/ -
8/21/2019 MDN_1403DS
14/108
http://www.aspose.com/ -
8/21/2019 MDN_1403DS
15/108
http://www.aspose.com/ -
8/21/2019 MDN_1403DS
16/108
msdn magazine12
In our last column(msdn.microsoft.com/magazine/dn574801 ), we discussedthe current technology landscape or machine-to-machine (MM)computing, which reers to technologies that interconnect devices,usually or industrial instrumentation, in the orm o sensors or meters.Te prolieration o affordable and easy-to-program tiny computershas expanded this concept into whats called the Internet-o-Tings
(Io), opening the door to scenarios where even ordinary homeappliances can be controlled or used as sources o inormation togenerate events. Tis way, it isnt diffi cult to send alerts when its timeto replenish the ridge, automatically close the window blinds asnight alls or set the thermostat based on the amily habits.
We also made the case or using the Windows Azure Service Bus ordevice connectivity, as an alternative to using a VPN, when trying tosolve the addressability, security, and perormance concerns associatedwith deploying a large number o sensors or meters. Tis is becomingincreasingly relevant considering that, according to the latest BI Intel-ligence report rom Business Insider, there will be more than billionconnections directly related to the Io by the year 1(read.bi/18L5cg8).
Using a designated Service Bus queue or topic or a deviceprovides an elegant way to incorporate resiliency and occasionalconnectivity or Io applications. In this article, well walk througha hands-on Windows Azure implementation that illustrates theseconcepts, designing a Service Bus blueprint with device queues,deploying a listening worker role in Cloud Services, and program-ming an Arduino device that executes commands sent remotelyby mobile clients, as shown in Figure 1.
I you look at the diagram, the Windows Azure Service Buscomponent becomes the centerpiece o the design, providing theauthentication, message distribution and scalability to supportthe multiple devices that will be sending data or receiving remote
commands. Te Service Bus is available in all Microsof datacentersthat offer Windows Azure services, and its backed up by a highlyredundant storage i nrastructure. Also, like all other WindowsAzure components, it offers an open and easy-to-understand RESinterace, along with multiple SDKs (Microsof .NE Framework,Java, PHP, Ruby, among others) built on top o it.
In our proposed architecture, devices talk to a .NE applicationrunning on Windows Azure Cloud Services, which acts as a gate-way to the Service Bus in order to simpliy the communicationprocess with its assigned queue. his approach ully enablesany o the our Io communication patterns described in ourprevious column: elemetry, Inquiry, Command and Notication.
Here, well implement a scenario in which a mobile device sendsa command to another device in order to execute an actioninthis case, turn an LED on or off. One o the benets o this solu-tion is that i the device is temporarily offl ine, it can pick up thecommands whenever it reconnects to the Internet. You can alsoset up an expiration time in a message to avoid the execution o atask at an inconvenient moment or schedule messages to be sentat a specic time in the uture.
For this example, well use the well-known, well-documentedArduino device, as described in our previous column. For themobile client portion o the proo-o-concept, well create aWindows Phone application.
Heres our simple scenario:1. When the Arduino device is started, it sends an identica-tion signal to the gateway application running on WindowsAzure Cloud Services. Te gateway creates a Service Bus
The Windows Azure Service Bus and theInternet of Things, Part 2
Code download available at msdn.microsoft.com/magazine/msdnmag0314.
WINDOWSAZUREINSIDERBRUNO TERKALY AND
RICARDO VILLALOBOS
BUILD A FREE DEV/TEST SANDBOX IN THE CLOUD
MSDN subscribers can quickly spin up a dev/test environment on
Windows Azure at no cost. Get up to $150 in credits each month!
aka.ms/msdnmag
Figure1An Internet-of-Things Architecture Using theWindows Azure Service Bus
TCP Connection
ArduinoTCP Connection
TCP Connection
REST Interface/SDKs
Windows Azure Service Bus
Windows AzureCloud Service
Mobile and Desktop Devices
http://msdn.microsoft.com/magazine/dn574801http://msdn.microsoft.com/magazine/dn574801http://msdn.microsoft.com/magazine/dn574801http://read.bi/18L5cg8http://read.bi/18L5cg8http://read.bi/18L5cg8http://msdn.microsoft.com/magazine/msdnmag0314http://aka.ms/msdnmaghttp://msdn.microsoft.com/magazine/msdnmag0314http://aka.ms/msdnmaghttp://read.bi/18L5cg8http://msdn.microsoft.com/magazine/dn574801 -
8/21/2019 MDN_1403DS
17/108
1March 2014msdnmagazine.com
queue for the device in case it doesnt exist, and establishesa CP connection, ready to send commands.
. A Windows Phone application sends a command to theWindows Azure Service Bus queue assigned to the device.
. Te message remains in the queue until the gateway appli-
cation picks it up and sends the command to the Arduinodevice via the established CP connection.. Te Arduino device turns the LED on or off based on
the command.Lets look at the steps to make this happen, one by one.Step 1: Create the Windows Azure Service Bus Namespace
Using your Windows Azure credentials (you can request a trialaccount at bit.ly/1atsgSa), log in to the Web portal and click on theSERVICE BUS section (see Figure 2). Select the CREAE option,and enter a name for your namespace. Ten, click on CONNEC-ION INFORMAION and copy the text in the Connection Stringbox, which youll need later.
Step 2: Create the Gateway Application and Deploy to WindowsAzure Cloud ServicesCode for the gateway application, whichretrieves messages from the Service Bus queue and relays the commandsto the Arduino device, is included with the code download (availableat msdn.microsoft.com/magazine/msdnmag0314).Its based on the work ofClemens Vaster, who kindly contributed his guidance and expertiseto this article. His original project can be found at bit.ly/L0uK0v .
Before we dive into this code, be sure you have Visual Studio1 installed, along with version . of the Windows Azure SDKfor .NE(bit.ly/JYXx5n). Te solution includes three different projects:
ArduinoListenercontains the main WorkerRole code. ConsoleListenerthe console version of the Arduino-
Listener, for local testing. MSDNArduinoListenerthe Windows Azure deploy-ment project for ArduinoListener.
If you inspect the ServiceConguration.cscfg les (for both cloudand local deployment) for the MSDNArduinoListener project,youll see a setting that stores the connection string for the ServiceBus. Replace its value with the one obtained in Step 1. Te rest isalready congured for the solution to work, including the deni-
tion of port 11 for receiving connections from the devices. Next,open the WorkerRole.cs le in the ArduinoListener project, wherethe main code is located.
Tere are four main sections to analyze.First, a cpListener is created, and connections from devices
are accepted:var deviceServer = new TcpListener(deviceEP);deviceServer.Start(10);try{ do { TcpClient connection = await deviceServer.AcceptTcpClientAsync(); if (connection != null) { ...
Once a connection with the device has been established, a Network-Stream is dened and set to listening mode. Te readBuffer variablewill contain the identier value sent by each Arduino device:
NetworkStream deviceConnectionStream = connection.GetStream();var readBuffer = new byte[64];if (await deviceConnectionStream.ReadAsync(readBuffer, 0, 4) == 4){ int deviceId = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(readBuffer, 0)); ...
Next, a queue is created based on the deviceId value (in case itdoesnt exist), and a message receiver object is dened(see Figure3). Ten, the device queue receiver is set to asynchronous mode topull messages (commands from the queue). Tis queue will store
commands sent by mobile devices, such as a Windows Phone.When a message is received in the queue, its content is inspected andif it matches the ON or OFF commands, the information is written
to the connection stream establishedwith the device(see Figure 4).
Notice that the message isntremoved from the queue (message.CompleteAsync) unless the writingoperation to the device connectionstream is successful. Also, in orderto keep the connection alive, thedevice is expected to send a ping
heartbeat. For this proof of concept,we arent expecting conrmation fromthe device when it receives the message.In a production system, however, thiswould be required to comply with thecommand pattern.
Step 3: Deploy the Arduino-
Listener Windows Azure Project
to Cloud Services Deploying theArduinoListener to Windows Azureis extremely simple. In Visual Studio1, right-click on the MSDN-
ArduinoListener project andselect the Publish option. Youll ndFigure 2Creating the Windows Azure Service Bus Namespace
http://www.msdnmagazine.com/http://www.bit.ly/1atsgSahttp://www.bit.ly/1atsgSahttp://www.bit.ly/1atsgSahttp://msdn.microsoft.com/magazine/msdnmag0314http://msdn.microsoft.com/magazine/msdnmag0314http://msdn.microsoft.com/magazine/msdnmag0314http://www.bit.ly/L0uK0vhttp://www.bit.ly/L0uK0vhttp://www.bit.ly/L0uK0vhttp://www.bit.ly/JYXx5nhttp://www.bit.ly/JYXx5nhttp://www.bit.ly/JYXx5nhttp://www.bit.ly/JYXx5nhttp://www.bit.ly/L0uK0vhttp://msdn.microsoft.com/magazine/msdnmag0314http://www.bit.ly/1atsgSahttp://www.msdnmagazine.com/ -
8/21/2019 MDN_1403DS
18/108* Offer valid for a limited time only. Complete packages come with a 30 day money back guarantee and no minimum contract term. The $7.99 per month price reflect s a 12 month
pre-payment option for the 1&1 Online Store Starter package. After 12 months, regular price of $9.99 per month applies. Some features listed are only available with package upgrade.
DOMAINS |E-MAIL |WEB HOSTING |eCOMMERCE |SERVERS
1&1 NEW
eCOMSELL MORE WITH APROFESSIONAL DESIGN.
Whether beginner or professional, create
your store online in a few easy steps
Choose from over a hundred high-qualitydesigns and templates between industries
Store links easily with an existing domainor your new included domain (free)*
Whether PC, tablet or smartphone yourshop will be displayed optimally onall devices
http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/ -
8/21/2019 MDN_1403DS
19/108
START SELLING NOW!
Visit www.1and1.com for billing information and full promotional details. Program and pricing specifications and availability subject to change without notice. 1&1 and the 1&1 logo are
trademarks of 1&1 internet, all other trademarks are the propert y of their respective owne rs. 2014 1&1 Internet. All right s reserved.
Call1 (877) 461-2631
TEST30 DAY MONEY
BACK GUARANTEE
MONTHFLEXIBLE PAYMENT
OPTIONS
CALLSPEAK WITH AN
EXPERT 24/7
1and1.com
MERCE1&1 ONLINE STORECOMPLETE PACKAGESstarting at
Try now! 30 day money back guarantee.$7.99month*
MORE POSSIBILITIES.
MORE SUCCESS.
Your shop can grow with yourbusiness
Target customers with specialpromotions and cross selling
Product rating capability: Buildtrust by letting customers sharefeedback
Sell internationally: Wide selectionof languages, currencies and
payment options
MAXIMUM RELIABILITY.
PROFESSIONAL SUPPORT.
Convenient shipping processingvia UPS, FedEx, etc.
Reliability through geo-redundant operation in twoseparate 1&1 Data Centers
24/7 expert customer serviceby experienced eCommerceprofessionals
FIND CUSTOMERS.
KEEP CUSTOMERS.
Search engine optimization (SEO):rank higher on Google and othersearch engines
Easy synchronization with Amazon,Ebay, and more
Easily create your own Facebook Store
Create customer loyalty by providingfree newsletters and coupons
http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/http://www.1and1.com/ -
8/21/2019 MDN_1403DS
20/108
msdn magazine16 Windows Azure Insider
specic instructions or the Publish Windows Azure ApplicationWizard atbit.ly/1iP9g2p. Afer completing the wizard, you end up witha cloud service located at xyz.cloudapp.net. Record this name, asyoull need it when you create the Arduino client in the next step.
Step 4: Program the Arduino Device to Talk to the Gateway
(Listener) Arduino devices offer a rich interace or perorming net-work operations using a simple Web client object. For our prototype,we decided to use the Arduino Uno R model(bit.ly/18ZlcM8), alongwith its corresponding Ethernet shield (bit.ly/1do6eRD). o install,interact and program Arduino devices using Windows, ollow theguide at bit.ly/1dNBi9R. Youll end up with an easy-to-use IDE (calledthe Arduino application), where you can write programs (calledsketches) using JavaScript, as shown in Figure 5.
Figure 6 shows the sketch or interacting with the ArduinoListener created in Step , and now deployed in Windows Azure.
Sketches or the Arduino have two main sections: setup andloop. Instructions in the setup section are executed once, and this
is where variables are initialized and connections established. Inour example, the Ethernet client and related values are dened, aserial connection (or debugging purposes) is established, and thepin where the LED is connected is initialized as an output port.
Code in the loop section is executed constantly, and it includestwo main blocks based on the statuso the CP connection between theArduino device and the listener run-ning in Windows Azure Cloud Services:connected or disconnected. When theconnection is established or the rsttime, a stopWatch object is started to
keep track o the time elapsed or theconnection. Also, the device identieris sent to the listener, to be used as thename o the queue where messages andcommands will be stored.
he code block that handles theArduino behavior afer the connec-tion has been established keeps tracko the time elapsed since the connec-tion was created, pinging the listenerevery , ms, to keep the con-nection alive when no commands are
received. Tis code also tries to readdata rom the listener, putting the
data into the bu array when it arrives. I a value o 1 is detected,the LED is turned on, i the value is , the LED is turned off. Testopwatch object is reset afer each command.
Once the sketch has been uploaded to the device, the code runs onthe Arduino controller in an innite loop, trying to connect to a cloudservice. When connected, it orwards the device id so the cloud serviceknows to which device its talking. Ten the code begins to read inputrom the cloud service, telling the device whether to turn on or off theLED light (in this case, its connected to digital port o the device).
Step 5: Creating a Windows Phone Client to Send to Device
QueueInteracting with the device is as simple as sending messagesto the device queue. As we mentioned at the beginning o the
article, the Windows Azure Service Bus provides a RES interacethat lets you interact with it rom multiple programming languages.Because theres no offi cial SDK or Windows Phone developers, weused one o the examples rom the Windows Phone community,which shows how to authenticate and interact with the Service
Bus using HP requests and theWebClient object. he source codeis also included with the code down-load, in the Visual Studio 1 projectcalled MSDNArduinoClient. Figure7shows the clients main screen, romwhich you send commands to the
Arduino device.Creating similar clients or other
mobile devices (including iOS andAndroid) wouldnt be diffi cult, as mosto them provide libraries to gener-ate RES commands using HPrequest clients. Moreover, its possibleto directly interact with the WindowsAzure Service Bus using traditionallanguages such as Java, PHP or Ruby,which simplies this process. TeseSDKs are published under an open
source license, and can be oundat github.com/WindowsAzure .
if (message != null){ Stream stream = message.GetBody(); StreamReader reader = new StreamReader(stream); string command = reader.ReadToEnd();
if (command != null) { switch (command.ToUpperInvariant()) { case "ON": await deviceConnectionStream.WriteAsync(OnFrame, 0, OnFrame.Length); await message.CompleteAsync(); break; case "OFF": await deviceConnectionStream.WriteAsync(OffFrame, 0, OffFrame.Length); await message.CompleteAsync(); break; } }}
Figure 4 Writing to the Connection Stream
Figure 5 The Arduino Application
var namespaceManager = NamespaceManager.CreateFromConnectionString(RoleEnvironment.GetConfigurationSettingValue("serviceBusConnectionString"));if (!namespaceManager.QueueExists(string.Format("dev{0:X8}", deviceId))){ namespaceManager.CreateQueue(string.Format("dev{0:X8}", deviceId));
}var deviceQueueReceiver = messagingFactory.CreateMessageReceiver( string.Format("dev{0:X8}", deviceId), ReceiveMode.PeekLock);do{ BrokeredMessage message = null; message = await deviceQueueReceiver.ReceiveAsync(); ...
Figure 3Creating a Queue
http://www.bit.ly/1iP9g2phttp://www.bit.ly/1iP9g2phttp://www.bit.ly/1iP9g2phttp://www.bit.ly/18ZlcM8http://www.bit.ly/18ZlcM8http://www.bit.ly/18ZlcM8http://www.bit.ly/1do6eRDhttp://www.bit.ly/1do6eRDhttp://www.bit.ly/1do6eRDhttp://www.bit.ly/1dNBi9Rhttp://www.bit.ly/1dNBi9Rhttp://www.bit.ly/1dNBi9Rhttp://www.github.com/WindowsAzurehttp://www.github.com/WindowsAzurehttp://www.github.com/WindowsAzurehttp://www.github.com/WindowsAzurehttp://www.bit.ly/1dNBi9Rhttp://www.bit.ly/1do6eRDhttp://www.bit.ly/18ZlcM8http://www.bit.ly/1iP9g2p -
8/21/2019 MDN_1403DS
21/108
1March 2014msdnmagazine.com
Wrapping UpBuilding an Internet-of-Things architectureusing the Windows AzureService Bus to managedevices and services con-nections provides an easyway to secure, scale andaddress clients individ-
ually without incurringcostly VPN solutions, withthe benefit of efficientlyhandling occasionallydisconnected scenarios.Queues act as dedicatedmailboxes where messagesbetween devices andservices are exchanged,supporting the differentcommunication use casesand patterns commonly
found in the eld. WindowsAzure provides a reliable,
geo-distributed and robust infrastructure for deploying the servicesrequired with a high volume of interconnected sensors andmetersa trend that will continue to grow in the years ahead.
BRUNOTERKALYis a developer evangelist or Microsof. His depth o knowledgecomes rom years o experience in the eld, writing code using a multitude oplatorms, languages, rameworks, SDKs, libraries and APIs. He spends timewriting code, blogging and giving live presentations on building cloud-basedapplications, specically using the Windows Azure platorm. You can read hisblog at blogs.msdn.com/b/brunoterkaly.
RICARDOVILLALOBOSis a seasoned sofware architect with more than yearso experience designing and creating applications or companies in multipleindustries. Holding different technical certications, as well as a masters degreein business administration rom the University o Dallas, he works as a cloudarchitect in the DPE Globally Engaged Partners team or Microsot, helpingcompanies worldwide to implement solutions in Windows Azure. You can readhis blog at blog.ricardovillalobos.com.
Terkaly and Villalobos jointly present at large industry conerences. Theyencourage readers o Windows Azure Insider to contact them or availability.Terkaly can be reached at [email protected] and Villalobos can be [email protected].
THANKSto the following Microsoft technical experts for reviewing this article:Abhishek Lal and Clemens Vasters
Figure6The Arduino Device Code
#include #include #include // Enter a MAC address and IP address for your controller below.// The IP address will be dependent on your local network,// and it's optional if DHCP is enabled.byte mac[] = { 0x90, 0xA2, 0xDA, 0x0D, 0xBC, 0xAE };static const byte deviceId[] = { 0x00, 0x00, 0x00, 0x01 };static const uint8_t ACK = 0x01;static const int LED_PIN = 8;int connected = 0;EthernetClient client;StopWatch stopWatch;long pingInterval = 200000;void setup(){ Serial.begin(9600); Serial.println("Initialized"); Ethernet.begin(mac); pinMode(LED_PIN, OUTPUT);}void turnLedOn(){ digitalWrite(LED_PIN, HIGH);}void turnLedOff(){ digitalWrite(LED_PIN, LOW);}void loop(){if ( connected == 0)
{ Serial.println("Trying to connect"); char* host = "xyz.cloudapp.net"; client.setTimeout(10000); connected = client.connect(host, 10100); if (connected)
{ Serial.println( "Connected to port, writing deviceId and waiting for commands..."); client.write(deviceId, sizeof(deviceId)); stopWatch.start(); }
else { Serial.println("Connection unsuccessful"); client.stop(); stopWatch.reset(); } } if (connected == 1) { if (stopWatch.elapsed() > pingInterval) { Serial.println("Pinging Server to keep connection alive..."); client.write(deviceId, sizeof(deviceId)); stopWatch.reset();
stopWatch.start(); } byte buf[16]; int readResult = client.read(buf, 1);
if (readResult == 0){
Serial.println("Can't find listener, disconnecting..."); connected = 0; stopWatch.reset(); } else if (readResult == 1) { Serial.println("Data acquired, processing..."); switch ( buf[0] ) { case 1: Serial.println("Command to turn led on received..."); turnLedOn(); break; case 2:
Serial.println("Command to turn led off received..."); turnLedOff(); break; } stopWatch.reset(); stopWatch.start(); } }}
Figure7The Windows Phone Cli-ent Interface
http://www.msdnmagazine.com/http://blogs.msdn.com/b/brunoterkalyhttp://blog.ricardovillalobos.com/mailto:[email protected]:[email protected]:[email protected]:[email protected]://blog.ricardovillalobos.com/http://blogs.msdn.com/b/brunoterkalyhttp://www.msdnmagazine.com/ -
8/21/2019 MDN_1403DS
22/108
msdn magazine18
Asynchronous code usingthe async and await keywords
is transorming the way programs are written, and with goodreason. Although async and await can be useul or server sofware,most o the current ocus is on applications that have a UI. Forsuch applications, these keywords can yield a more responsive UI.However, its not immediately obvious how to use async and awaitwith established patterns such as Model-View-ViewModel (MVVM).Tis article is the rst in a short series that will consider patternsor combining async and await with MVVM.
o be clear, my rst article on async, Best Practices in Asyn-chronous Programming(msdn.microsoft.com/magazine/jj991977 ), wasrelevant to all applications that use async/await, both client andserver. Tis new series builds on the best practices in that article
and introduces patterns specically or client-side MVVM appli-cations. Tese patterns are just patterns, however, and may notnecessarily be the best solutions or a specic scenario. I you nda better way, let me know!
As o this writing, the async and await keywords are supported
on a wide number o MVVM platorms: desktop (WindowsPresentation Foundation [WPF] on the Microsof .NET Framework and higher), iOS/Android (Xamarin), Windows Store (Windows and higher), Windows Phone (version . and higher), Silverlight(version and higher), as well as Portable Class Libraries (PCLs)targeting any mix o these platorms (such as MvvmCross). Tetime is now ripe or async MVVM patterns to develop.
Im assuming youre somewhat amiliar with async and awaitand quite amiliar with MVVM. I thats not the case, there are anumber o helpul introductory materials available online. My blog(bit.ly/19IkogW) includes an async/await intro that lists additionalresources at the end, and the MSDN documentation on async is
quite good (search or Task-based Asynchronous Programming).For more inormation on MVVM, I recommend pretty muchanything written by Josh Smith.
A Simple ApplicationIn this article, Im going to build an incredibly simple application,as Figure 1shows. When the application loads, it starts an HPrequest and counts the number o bytes returned. he HPrequest may complete successully or with an exception, and theapplication will update using data binding. Te application is ullyresponsive at all times.
First, though, I want to mention that I ollow the MVVM pattern
rather loosely in my own projects, sometimes using a properdomain Model, but more oten using a set o services and data
A S YN C P ROG RA M M I N G
Patterns forAsynchronousMVVM Applications:Data BindingStephen Cleary
This article discusses:
Combining asynchronous programming with the MVVM pattern
Developing an asynchronous data-bound property
Common mistakes with ViewModels
An approach thats data-binding friendly
Technologies discussed:
Asynchronous Programming, MVVM
http://msdn.microsoft.com/magazine/jj991977http://msdn.microsoft.com/magazine/jj991977http://msdn.microsoft.com/magazine/jj991977http://www.bit.ly/19IkogWhttp://www.bit.ly/19IkogWhttp://www.bit.ly/19IkogWhttp://www.bit.ly/19IkogWhttp://msdn.microsoft.com/magazine/jj991977 -
8/21/2019 MDN_1403DS
23/108
1March 2014msdnmagazine.com
transfer objects (essentially a data access layer) instead of an actualModel. Im also rather pragmatic when it comes to t he View; Idont shy away from a few lines of codebehind if the alternative isdozens of lines of code in supporting classes and XAML. So, whenI talk about MVVM, understand that Im not using any particularstrict denition of the term.
One of the rst things you have to consider when introducing
async and await to the MVVM pattern is identifying which parts ofyour solution need the UI threading context. Windows platformsare serious about UI components being accessed only from the UIthread that owns them. Obviously, the view is entirely tied to theUI context. I also take the stand in my applications that anythinglinked to the view via data binding is tied to the UI context.Recent versions of WPF have loosened this restriction, allowingsome sharing of data between the UI thread and backgroundthreads (for example, BindingOperations.EnableCollection-Synchronization). However, support for cross-thread data bindingisnt guaranteed on every MVVM platform (WPF, iOS/Android/Windows Phone, Windows Store), so in my own projects I just
treat anything data-bound to the UI as having UI-thread affi nity.As a result, I always treat my ViewModels as though theyre
tied to the UI context. In my applications, the ViewModel is moreclosely related to the View than the Modeland the ViewModellayer is essentially an API for t he entire application. he Viewliterally provides just the shell of UI elements in which the actualapplication exists. Te ViewModel layer is conceptually a testableUI, complete with a UI thread affi nity. If your Model is an actualdomain model (not a data access layer) and theres data bindingbetween the Model and ViewModel, then the Model itself alsohas UI-thread affi nity. Once youve identied which layers haveUI affi nity, you should be able to draw a mental l ine between the
UI-affi ne code (View and ViewModel, and possibly the Model)
and the UI-agnostic code (probably the Model and denitely allother layers, such as services and data access).
Furthermore, all code outside the View layer (that is, the View-Model and Model layers, services, and so on) should not depend onany type tied to a specic UI platform. Any direct use of Dispatcher(WPF/Xamarin/Windows Phone/Silverlight), CoreDispatcher
(Windows Store), or ISynchronizeInvoke (Windows Forms) is abad idea. (SynchronizationContext is marginally better, but barely.)For example, theres a lot of code on the Internet that does someasynchronous work and then uses Dispatcher to update the UI; amore portable and less cumbersome solution is to use await forasynchronous work and update the UI without using Dispatcher.
ViewModels are the most interesting layer because they have UIaffi nity but dont depend on a specic UI context. In this series, Illcombine async and MVVM in ways that avoid specic UI typeswhile also following async best practices; this rst article focuseson asynchronous data binding.
Asynchronous Data-Bound Propertieshe term asynchronous property is actually an oxymoron.Property getters should execute immediately and retrieve currentvalues, not kick off background operations. Tis is likely one of thereasons the async keyword cant be used on a property getter. If yound your design asking for an asynchronous property, considersome alternatives rst. In particular, should the property actuallybe a method (or a command)? If the property getter needs to kickoff a new asynchronous operation each time its accessed, thats nota property at all. Asynchronous methods are straightforward, andIll cover asynchronous commands in another article.
In this article, Im going to develop an asynchronous data-bound
property; that is, a d ata-bound property that I update with theresults of an async operation. One common scenario is when aViewModel needs to retrieve data from some external source.
As I explained earlier, for my sample application, Im going todene a service that counts the bytes in a Web page. o illustratethe responsiveness aspect of async/await, this service will alsodelay a few seconds. Ill cover more realistic asynchronous servicesin a later article; for now, the service is just the single methodshown in Figure 2.
Figure 1The Sample Application
using System;using System.Net.Http;using System.Threading.Tasks;public static class MyStaticService{ public static async Task CountBytesInUrlAsync(string url) { // Artificial delay to show responsiveness. await Task.Delay(TimeSpan.FromSeconds(3)).ConfigureAwait(false);
// Download the actual data and count it. using (var client = new HttpClient()) { var data = await client.GetByteArrayAsync(url).ConfigureAwait(false); return data.Length; } }
}
Figure 2 MyStaticService.cs
http://www.msdnmagazine.com/http://www.msdnmagazine.com/ -
8/21/2019 MDN_1403DS
24/108
msdn magazine20 Async Programming
Note that this is considered a service, so its UI-agnostic. Becausethe service is UI-agnostic, it uses CongureAwait(false) every timeit does an await (as discussed in my other article, Best Practices inAsynchronous Programming).
Lets add a simple View and ViewModel that starts an HPrequest on startup. Te example code uses WPF windows with
the Views creating their ViewModels on construction. Tis is justfor simplicity; the async principles and patterns discussed in thisseries of articles apply across all MVVM platforms, frameworksand libraries. he View for now will consist of a single mainwindow with a single label. Te XAML for the main View just bindsto the UrlByteCount member:
Te codebehind for the main window creates the ViewModel:public partial class MainWindow{ public MainWindow() { DataContext = new BadMainViewModelA(); InitializeComponent(); }}
Common MistakesYou might notice the ViewModel type is called BadMainView-ModelA. his is because Im going to first look at a couple ofcommon mistakes relating to ViewModels. One common mistakeis to synchronously block on the operation, like so:
public class BadMainViewModelA{ public BadMainViewModelA() { // BAD CODE!!! UrlByteCount =
MyStaticService.CountBytesInUrlAsync("http://www.example.com").Result; }
public int UrlByteCount { get; private set; }}
Tis is a violation of the async guideline async all the way, butsometimes developers try this if they feel theyre out of options.If you execute that code, youll see it works, to a certain extent.Code that uses ask.Wait or ask.Result instead of await issynchronously blocking on that operation.
Tere are a few problems with synchronous blocking. Te mostobvious is the code is now taking an asynchronous operation andblocking on it; by doing so, it loses all the benets of asynchronicity.If you execute the current code, youll see the application doesnothing for a few seconds, and then the UI window springs fullyformed into view with its results already populated. Te problemis the application is unresponsive, which is unacceptable for manymodern applications. Te example code has a deliberate delay toemphasize that unresponsiveness; in a real-world application, thisproblem might go unnoticed during development and show up onlyin unusual client scenarios (such as loss of network connectivity).
Another problem with synchronous blocking is more subtle: Tecode is more brittle. My example service uses CongureAwait(false)
properly, just as a service should. However, this is easy to forget,especially if you (or your coworkers) dont regularly use async.Consider what could happen over time as the service code is main-tained. A maintenance developer might forget a CongureAwait,and at that point the blocking of the UI thread would become adeadlock of the UI thread. (Tis is described in more detail in my
previous article on async best practices.)OK, so you should use async all the way. However, many devel-
opers proceed to the second faulty approach, illustrated in Figure 3.Again, if you execute this code, youll nd that it works. Te UI
now shows immediately, with in the label for a few secondsbefore its updated with the correct value. Te UI is responsive, andeverything seems ne. However, the problem in this case is han-dling errors. With an async void method, any errors raised by theasynchronous operation will crash the application by default. Tis isanother situation thats easy to miss during development and showsup only in weird conditions on client devices. Even changing thecode in Figure 3from async void to async ask barely improves the
application; all errors would be silently ignored, leaving the userwondering what happened. Neither method of handling errors isappropriate. And though its possible to deal with this by catchingexceptions from the asynchronous operation and updating otherdata-bound properties, that would result in a lot of tedious code.
A Better ApproachIdeally, what I really want is a type just like ask with propertiesfor getting results or error details. Unfortunately, ask is notdata-binding friendly for two reasons: it doesnt implement INotify-PropertyChanged and its Result property is blocking. However, youcan dene a ask watcher of sorts, such as the type inFigure 4.
using System.ComponentModel;using System.Runtime.CompilerServices;public sealed class BadMainViewModelB : INotifyPropertyChanged{ public BadMainViewModelB() { Initialize(); }// BAD CODE!!!
private async void Initialize() {
UrlByteCount = await MyStaticService.CountBytesInUrlAsync( "http://www.example.com"); }private int _urlByteCount;
public int UrlByteCount { get { return _urlByteCount; } private set { _urlByteCount = value; OnPropertyChanged(); } }public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged([CallerMemberName] string propertyName = null) { PropertyChangedEventHandler handler = PropertyChanged; if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName)); }
}
Figure 3BadMainViewModelB.cs
-
8/21/2019 MDN_1403DS
25/108
pu page. lem n s, , ; ersion page. lemen s, , ; ersion up page. lemen s, , ; ersii n up page. lemen s, , ; pa
48 , ; ersion age.Elemen s, 0, 405 ;AddUP Version up2 page.Elements, 240, 405 ;AddUP VersionE up5 pa l. ll men s,, , ; thepage othedocument documen
Rec ngl el nts,EA N 13Bar o e, x, y, 204, 99 ; Bar o ebar ode = new Ean13 123456789012, x, y+ 1 ; bar o . += - r e. e ymbolWid 2; elements.Add bar
elem ne s,, JAN 13 B r ode,2 digitsupplement, x,y, 204,99 ; ar ode bar ode = new Ean1 up , x, + bar o e. += 4 - bar ode. et ymbolWidth 2; ele
oat y){ dd ptionAndRect ngle(elements, EAN/JAN13 Bar Code, 5 digit supplement, x, y,204, 99); B rCode b r o e new 13Sup5(1234 678901212345, x, y+ 21); barCode.X +=(204
onA( roup ele enm ts, floatx, fl ty) { AddCaptionAndRectangle(elements, UPC VersionA Bar Code,x, y 2, 04, 9 ; rB Code ar ode= n w UpcVersionA(12345678901, x,y +21); barCode.X+
onA (p Gr pelements,, fl t , floaty) { AddCaptionAndRectangle(elements, UPCVersion E Bar Code, 2 digii su pleme , , y, 204, 99);BarCo ebar ode= new UpcVersionASup2(123456
ode); private v idAddU C irs onASup5(Group elements, floatx, float y) { AddCaptionAndRectangle(ele ent , PC rsion EBar Code, 5 di it supplement,x, y, 204, 99);BarCodebarCode=
bolWi th(dt )) / ;2 elements. d ( rba Code); }private void AddE NA 8(Group elements, float x, float y) { Ad ap ition nd ngle(ele ents,EAN/JA 8 Bar Co e, x, y, 204, 99); BarCode barCode =n
g.Titll Open ile Dialo ; leDialog.Filter = obe PD file (*.pdf)|*.pdf|All Files(*.*)|*.*; if(file iial .l . ow iall () == Dialo Result.OK) { pdfViewer.OpenFile(fileDialog.FileName, ); } S ve
; a eFileDi loal g.Filter = oAd bePDF files (*.pdf)|*.pdf|AllFiles (.*)|*.*; if (saveFileDialog.Sho Di li lo = iiiai logRes llt . K) { pdf iewer.SaveAs(saveFile ii log.FileName ; if
; } els { M sse geBox.Sho ( lease opena file to print); } penFileDialog fileDialol = ew O nFile ialog(); file Dialog.Tiitle = OpenFile Dial ; filleDialog.InitialDir ct ry = @c: ; fileDl ia
R uls t. K) { y amicPDFViewerClass test= n Dw yna icPDFVi erCr lass(); PD iPri ter p irii er test.O nFileFor ri ter l(fil Di log.FileName); rinter.PrintQ ii t(); } b
G HC le g h= GCHandle.Alll oc(contents,GC andleType.Pinne ); IntPtr con IntPtr g h. ddrOfPin edObjec ()t ; df Viewer.O nBuffer
e Elle ent:, , y);pageElements.Add(new Bookmark( ookmarked Text, ,+ y +20,p en Outline)); pa eElemen s.t dd (new Label(Thi text is bo k ar d ,. ,
, o ta x, flo t y) {//Addsa circl to thepageEllem ntsAddCapti n nd ectangle(p g lel te s, Circle P ge Ele nt:, x, y); pa leElements..A new C
ri a void dF rmatt dTextArea(Group pa Elemen s,floa x, oa y) /{ / d a rma edtext area o hepage lle ments stringfor a dHtml =< > i>Dynamic< D>P F ; Gen
pportf r text at t ppears inthe ocument. o ha e + compll e c ntr l e paragra ph roperties: spacing b for , spacingafter, rst liine + indentation, left indentatiion, right ii nde atioi ,
= imTi >font acf e, < on c lll rll =FF 00>col r, bb old, / > i>italic and underlinel o >< hisis a very imple HT
er=\1\>100200 + 300400500600 o y>;C nv rsion.. onv r.ConvertHtmlString(s pll Htmll
ath.Combine(GetPath(), LetterPortrait.p f)); printJ b.DocumentNam = LettL er Portrait; if(printJob.Printer.Color) p iiiini tJ . rintOption Co. lor = u ; ifi iprini ob.Printer. ollate) printJo P.. rint p ii
i
,
http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.com/http://www.dynamicpdf.c