MDN 1507DS
MDN 1507DS
MDN 1507DS
magazine
Code Maps in
Visual Studio 2015...............26
0715msdn_CoverTip_8x10.75.indd 1
6/8/15 11:57 AM
0715msdn_CoverTip_8x10.75.indd 2
6/8/15 11:58 AM
magazine
Code Maps in
Visual Studio 2015...............26
COLUMNS
FIRST WORD
Journey to Windows 10
Keith Boyd, page 6
Stephen Cleary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
UPSTART
Nicola Delfino . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
Bruno Terkaly . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
Giovanni Dicanio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
James McCaffrey . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
DATA POINTS
TEST RUN
0715msdn_C1_v1.indd 1
6/8/15 2:28 PM
Untitled-1 2
6/4/15 10:52 AM
Purpose:
Invoice
Expense Report
Microsoft Conference
Statement:
K-2014-05-08-7786
Pay Period:
5/1/2014 to 5/31/2014
FROM
TO
Quick Facts
Invoice Number:
Order Date:
Check
6/15/2015
Product Code
Product
BK-R50R-44
Road-650 Red, 44
BK-R68R-52
Road-450 Red, 52
Name:
Joey Santana
Department: HR
Payment Options
43660
6/3/2015
Payment Due:
Employee Information
Credit Card
Qty
Line Total
$419.46
Image
$419.46
$874.79
Account
5/1/2014
Unit Price
Date
Position:
Manager:
Description
234452
Housing
Business trip
SSN:
Employee #:
Transport
Fuel
Meals
Tax Amount:
Total
$.00
$200.00
$310.00
$123.00
$3,322.00
$133.00
$2,188.00
$.00
$200.00
$320.00
$22.00
$3,987.00
5/2/2014
234453
Business trip
234452
Business trip
$223.00
5/12/2014
$7,322.00
234452
$.00
Business trip
$203.00
$320.00
$.00
$3,322.00
$133.00
$200.00
$8,201.00
$203.00
$320.00
$.00
$4,045.00
$200.00
$806.00
$1,270.00
$288.00
$569.00
$15,288.00
$38.83
$1,716.18
Misc
$1,322.00
$124.25
Total Due:
Entertainment
$223.00
$1,553.10
Freight:
123-3234-2342
HR-77867622
5/3/2014
$874.79
Sub Total:
Manager
BM
Subtotal:
$18,421.00
Advances:
$10,000.00
TOTAL:
$8,421.00
1 of 1
Invoice: 43660
1 of 1
gy Result
BACTA MEDICAL
CENTRE
COLLECTED:
RECEIVED:
Jerome Morrow
M
AGE: 49
DOB: 01/10/19
61
Patient
NAME:
GENDER:
ORDERED BY:
PETER ANDERSEN
9976 KINGS FALLS DR
Account Number
Verification Code
Bill Date
Current Charges Past Due
After
Your results
PREVIOUS BILL
AMOUNT
3.3
mg/dL
Desirable
Your
Average Risk
disease
10+
$87.00
METER
NUMBER
242453
02 (30 Days)
PAYMENTS
(-)
$87.00
METER READINGS
PREVIOUS
PRESENT
79042
79137
NEW CHARGES
(+)
ADJUSTMENTS
(+ OR -)
$23.04
124423897723
6
12/03/2014
12/29/2014
$0.00
$23.04
MULTIPLIER
TOTAL
USAGE
RATE SCHEDULE
DESCRIPTION
95 KWH
RE - Residential Srv
AMOUNT
Purcha
PO1885
20.93
Sales Tax
Amount Due
265
SHIPPING L
2.11
23.04
mg/dL
Desirable
200
Borderline
240
280+
High
233
mg/dL
Optimal
130
Borderline high
32
190
Very High
260+
Your risk
40
60
Borderline
Optimal
100+
15%
Untitled-1 3
Avoid drinking
alcohol, except in
mocderation: one to
two drinks per day.
9912787381272348
What now?
mg/dL
Low
Quick Payment
Consider
retesting
in one to two
weeks, in case
your CRP level was
caused by
infection.
2477420000000000
032378
PETER ANDERSEN
9976 KINGS FALLS DR
26823 SAN FRANCISCO
PO BOX 77872
SAN FRANCISCO CA 78279
-8782
0 88
88
CREDIT CODE
Account Number
Verification Code
Bill Date
Current Charges Past Due
After
SHIPPING LAB
3
124423897723
6
12/03/2014
12/29/2014
6/4/15 10:52 AM
Purchase Or
PO18444174
magazine
ART STAFF
Henry Allain
Richard Vitale
Michael J. Valenti
2 msdn magazine
0715msdn_Masthead_v3_2.indd 2
6/8/15 2:18 PM
Untitled-19 1
6/2/15 5:42 PM
Editors NotE
MICHAEL DESMOND
Who We Are
In May we completed our biannual survey of MSDN Magazine
subscribers. This is the third such survey weve conducted since
2011, and the results provide a valuable picture of the evolving
MSDN Magazine readership.
For instance, did you know that MSDN Magazine readers are
getting younger? Its true. This year, 31 percent of respondents
report having 20 or more years of experience in the industry,
versus 37.7 percent in 2013 and 36 percent in 2011. At the same time,
the percentage of subscribers with less than 10 years of experience
has risen, from 22 percent in 2011 and 2013 to 26.4 percent this year.
Visit us at msdn.microsoft.com/magazine. Questions, comments or suggestions for MSDN Magazine? Send them to the editor: [email protected].
2015 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 Magazine or any part of MSDN
Magazine. If you have purchased or have otherwise properly acquired a copy of MSDN Magazine in paper format, you are permitted to physically transfer this paper copy in unmodified form. Otherwise, you are not permitted to transmit
copies 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 Magazine is published by 1105 Media, Inc. 1105 Media, Inc. is an independent company not affiliated with Microsoft Corporation. Microsoft Corporation is solely responsible for the editorial contents of this magazine. The
recommendations and technical guidelines in MSDN Magazine are based on specific environments and configurations. These recommendations or guidelines may not apply to dissimilar configurations. Microsoft Corporation does not make
any 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 are
used by 1105 Media, Inc. under license from owner.
4 msdn magazine
0715msdn_DesmondEdNote_v3_4.indd 4
6/8/15 2:15 PM
Untitled-1 1
12/2/14 4:42 PM
First Word
KEITH BOYD
Journey to Windows 10
In 2001 I received my first Microsoft Ship It awards for Internet
Explorer (IE) 6 and Windows XP. The initial reaction to Windows
XP is humorous in hindsight. Pundits were aghast at the new Aero
UI and predicted doom for the first Windows release featuring a
combined Windows 9x and NT kernel. For a few months, sales
were tepid, and Microsofties everywhere held their breath. Then
there was a collective exhale as consumers and businesses made
Windows XP a smash hit.
Sure, there were problems along the waythe number of exploits
in Windows XP forced the entire company to stop and spend
months on end doing a security push. To this day, there are copies
of David LeBlancs Writing Secure Code on shelves all over
Microsoft. Windows XP might have been chock full of security
holes, but it was subsequently hardened, improved upon, and to this
day remains one of the most beloved products in Microsoft history.
Microsoft began the Windows Vista project with its mojo intact.
Even on machines
without touch, Windows 8.1 is
easy to use and navigate.
As Windows Vista development began, the IE team was famously
dismantled, in favor of a new team tasked to build a modern,
connected-client platform. The Avalon team (of which I was a
part) built the managed application platform known as Windows
Presentation Foundation, or WPF. Throughout the myriad missteps of the Vista project, my conviction about WPF as a platform
that could propel Microsoft forward was resolute.
Alas, the travails of Windows Vista are well documented. We
finally shipped five and a half years later, and while there was
legitimate excitement for WPF and other new technologies, Windows
Vista failed to ignite the virtuous cycle that propelled the PC industry like past releases. It was the first legitimate dud in a long time.
Enter Steven Sinofsky.
Much like the Star Trek movie franchise, Windows was enjoying
success with every other release. Sinofsky aimed to stop that by
infusing a new confidence and culture in the Windows team, and
under his stewardship he produced the widely respectedand
even lovedWindows 7. But also staying true to the Star Trek
analogy, that same leadership team, riding a high similar to that
Enterprise (C&E) division at Microsoft. In that capacity, he oversees editorial strategy for MSDN Magazine. Prior to arriving in C&E in 2013, he held the same role
in Windows. When hes not at work, hes enjoying time with his family, including
his wife, Leslie, and three sons, Aiden, Riley and Drew.
6 msdn magazine
0715msdn_BoydFirstWord_v3_6.indd 6
6/8/15 2:27 PM
Untitled-1 1
10/13/11 11:25 AM
Upstart
RYDER DONAHUE
8 msdn magazine
0715msdn_DonahueUpstart_v3_8.indd 8
6/8/15 2:31 PM
/update/2015/07
Experience the brand new look at www.componentsource.com
BEST SELLER
BEST SELLER
NEW RELEASE
Add powerful PDF read, write, view & editing functionality to desktop, tablet & mobile applications.
View PDF files as raster in .NET, WinRT and C/C++
Merge, Split, Convert, Linearize and Distill PDF files
Read and Extract text, hyperlinks, metadata and more from PDF
Create the smallest file possible utilizing advanced PDF Optimizer
Convert PDF to an image format such as JPEG or TIFF
NEW RELEASE
1996-2015 ComponentSource. All Rights Reserved. All prices correct at the time of press. Online prices may vary from those shown due to daily fluctuations & online discounts.
US Headquarters
ComponentSource
650 Claremore Prof Way
Suite 100
Woodstock
GA 30188-5188
USA
Untitled-3 1
European Headquarters
ComponentSource
2 New Century Place
East Street
Reading, Berkshire
RG1 4ET
United Kingdom
(888) 850-9911
www.componentsource.com
6/1/15 11:33 AM
Cutting EdgE
DINO ESPOSITO
Message-Based Architecture
While observing the real world, youll see actions in process and
events that result from those actions. Actions and events carry data
and sometimes generate new data, and thats the point. Its just data.
You dont necessarily need a full-fledged object model to support
Figure 1 Defining the Base Message Class
public class Message
{
public DateTime TimeStamp { get; proteted set; }
public string SagaId { get; protected set; }
}
public class Command : Message
{
public string Name { get; protected set; }
}
public class Event : Message
{
// Any properties that may help retrieving
// and persisting events.
}
10 msdn magazine
0715msdn_EspositoCEdge_v3_10-13.indd 10
6/8/15 2:32 PM
Untitled-1 1
5/7/15 12:58 PM
interface IBus
Send<T>(T command) where T : Command;
RaiseEvent<T>(T theEvent) where T : Event;
RegisterSaga<T>() where T : Saga;
RegisterHandler<T>();
void IBus.RegisterSaga<T>()
{
var sagaType = typeof(T);
var messageType = sagaType.GetInterfaces()
.First(i => i.Name.StartsWith(typeof(IStartWith<>).Name))
.GenericTypeArguments
.First();
RegisteredSagas.Add(messageType, sagaType);
}
void IBus.Send<T>(T message)
{
SendInternal(message);
}
void IBus.RegisterHandler<T>()
{
RegisteredHandlers.Add(typeof(T));
}
void IBus.RaiseEvent<T>(T theEvent)
{
EventStore.Save(theEvent);
SendInternal(theEvent);
}
void SendInternal<T>(T message) where T : Message
{
// Step 1: Launch sagas that start with given message
// Step 2: Deliver message to all already running sagas that
// match the ID (message contains a saga ID)
// Step 3: Deliver message to registered handlers
}
12 msdn magazine
0715msdn_EspositoCEdge_v3_10-13.indd 12
A saga is a component that declares the following information: a command or event that starts the business process associated with the saga,
the list of commands the saga can handle, and the list of events in which
the saga is interested. A saga class implements interfaces through which
it declares the commands and events that are of interest. Interfaces like
IStartWith and ICanHandle are defined as follows:
public
{
void
}
public
{
void
}
6/8/15 2:32 PM
Instantly Search
Terabytes of Text
dtSearchs document filters
support popular file types, emails
with multilevel attachments,
databases, web data
Wrapping Up
dtSearch.com 1-800-IT-FINDS
msdnmagazine.com
0715msdn_EspositoCEdge_v3_10-13.indd 13
6/8/15 2:32 PM
Untitled-5 2
4/2/15 11:44 AM
Untitled-5 3
4/2/15 11:45 AM
KENNY KERR
The first thing Ill do is take care of unloading the DLL, which Ill call
the component from here on. The component should support unload
queries via an exported function call, DllCanUnloadNow, and its
the application that controls the unloading with the CoFreeUnusedLibraries function. I wont spend much time on this because this is
the same way components were unloaded in classic COM. Because
the component isnt statically linked into the applicationwith a LIB
file, for examplebut is instead loaded dynamically via the LoadLibrary function, there needs to be some way for the component to
be unloaded eventually. Only the component really knows how many
outstanding references are being held so the COM runtime can call its
DllCanUnloadNow function to determine whether its safe to unload.
Each object can then simply increment this lock in its constructor
and decrement it in its destructor. To keep that simple, Ill write a
little ComponentLock class:
struct ComponentLock
{
ComponentLock() noexcept
{
InterlockedIncrement(&s_lock);
}
~ComponentLock() noexcept
{
InterlockedDecrement(&s_lock);
}
};
Any and all objects that should prevent the component from
unloading can then simply embed a ComponentLock as a member
variable. The DllCanUnloadNow function can now be implemented
quite simply:
HRESULT __stdcall DllCanUnloadNow()
{
return s_lock ? S_FALSE : S_OK;
}
There are really two types of objects you can create within a
componentactivation factories, which were called class factories
in classic COM, and the actual instances of some particular class.
Im going to implement a simple Hen class and Ill start by defining
an IHen interface so the hen can cluck:
struct __declspec(uuid("28a414b9-7553-433f-aae6-a072afe5cebd")) __declspec(novtable)
IHen : IInspectable
{
virtual HRESULT __stdcall Cluck() = 0;
};
};
16 msdn magazine
0715msdn_KerrWinCPP_v5_16-18.indd 16
6/8/15 2:16 PM
};
The component allows applications to retrieve a specific activation factory by exporting another function called DllGetActivationFactory. This, again, is analogous to the DllGetClassObject
exported function that supports the COM activation model. The
main difference is that the desired class is specified with a string
rather than a GUID:
HRESULT __stdcall DllGetActivationFactory(HSTRING classId,
IActivationFactory ** factory) noexcept
{
}
Now I need to get the backing buffer for the HSTRING class
identifier:
wchar_t const * const expected = WindowsGetStringRawBuffer(classId, nullptr);
I can then compare this value with all of the classes my component
happens to implement. So far theres only one:
if (0 == wcscmp(expected, L"Sample.Hen"))
{
*factory = new (std::nothrow) HenFactory;
return *factory ? S_OK : E_OUTOFMEMORY;
}
msdnmagazine.com
0715msdn_KerrWinCPP_v5_16-18.indd 17
Thats all the C++ I need to get this simple component up and
running, but theres still a bit more work to do in order to actually
make a DLL for this component and then describe it to those pesky
C# compilers that dont know how to parse header files. To make
a DLL, I need to involve the linker, specifically its ability to define
the functions exported from the DLL. I could use the Microsoft
compiler-specific dllexport __declspec specifier, but this is one
of the rare cases where I prefer to talk to the linker directly and
instead provide a module-definition file with the list of exports. I
find this approach less error prone. So its back to the console for
the second source file:
C:\Sample>notepad Sample.def
This DEF file simply needs a section called EXPORTS that lists
the functions to be exported:
EXPORTS
DllCanUnloadNow
PRIVATE
DllGetActivationFactory PRIVATE
I can now provide the C++ source file along with this moduledefinition file to the compiler and linker to produce the DLL, and
then use a simple batch file as a convenience to build the component and place all of the build artifacts in a subfolder:
C:\Sample>type Build.bat
@md Build 2>nul
cl Sample.cpp /nologo /W4 /FoBuild\ /FeBuild\Sample.dll /link /dll /def:Sample.def
Ill gloss over the deep magic that is the batch file scripting language and focus on the Visual C++ compiler options. The /nologo
option suppresses the display of the copyright banner. The option
is also forwarded to the linker. The indispensable /W4 option tells
the compiler to display more warnings for common coding bugs.
Theres no /FoBuild option. The compiler has this hard-to-read
convention whereby output paths follow the option, in this case
/Fo, without a space in between. Anyway, the /Fo option is used
to coerce the compiler to dump the object file in the Build subfolder. Its the only build output that doesnt default to the same
output folder as the executable defined with the /Fe option. The
/link option tells the compiler that subsequent arguments are to be
interpreted by the linker. This avoids having to call the linker as
a secondary step and, unlike the compiler, the linkers options are
case-insensitive and do employ a separator between the name of
an option and any value, as is the case with the /def option that
indicates the module-definition file to use.
I can now build my component quite simply and the resulting
Build subfolder contains a number of files, only one of which matters. Naturally, thats the Sample.dll executable that can be loaded
into the applications address space. But this is not enough. An
application developer needs some way to know what the component contains. A C++ developer would probably be satisfied with
a header file including the IHen interface, but even that isnt particularly convenient. The Windows Runtime includes the concept of
language projections whereby a component is described in such a
way that different languages can discover and project its types into
their programming models. Ill explore language projection in the
coming months, but for now lets just get this sample to work from
July 2015 17
6/8/15 2:16 PM
a C# application because thats the most convincing. As I mentioned, C# compilers dont know how to parse C++ header files,
so I need to provide some metadata with which the C# compiler
will be happy. I need to produce a WINMD file that contains
the CLR metadata describing my component. This is no simple
matter because the native types I might use for the components ABI
can often look very different when projected into C#. Fortunately,
the Microsoft IDL compiler has been repurposed to produce a
WINMD file, given an IDL file that uses a few new keywords. So
its back to the console for our third source file:
C:\Sample>notepad Sample.idl
This is good old IDL and if youve used IDL in the past to define
COM components, you shouldnt be surprised by any of this. All
Windows Runtime types must, however, define a version attribute. This used to be optional. All interfaces must also derive from
IInspectable directly. Theres effectively no interface inheritance in
the Windows Runtime. This has some negative consequences that
Ill talk about in the coming months.
0715msdn_KerrWinCPP_v5_16-18.indd 18
Ill again gloss over the magic in the batch file and focus on whats
new with the MIDL compiler options. The /winrt option is the key
and indicates that the IDL file contains Windows Runtime types
rather than traditional COM or RPC-style interface definitions.
The /out option just ensures that the WINMD file resides in the
same folder as the DLL as this is required by the C# toolchain. The
/metadata_dir option tells the compiler where it can find the metadata that was used to build the OS. As I write this, the Windows
SDK for Windows 10 is still settling down and I need to be careful
to invoke the MIDL compiler that ships with the Windows SDK
and not the one provided by the path in the Visual Studio tools
command prompt.
Running the batch file now produces both the Sample.dll and
the Sample.winmd, which I can then reference from a C# Windows
Universal app and use the Hen class as if it were just another CLR
library project:
Sample.Hen h = new Sample.Hen();
h.Cluck();
for Pluralsight and a Microsoft MVP. He blogs at kennykerr.ca and you can
follow him on Twitter at twitter.com/kennykerr.
ThanKs to the following Microsoft technical expert for reviewing this article:
Larry Osterman
6/8/15 2:16 PM
1&1 DEDICATED
SERVER
BUSINESS LINE
TRY FOR
30 DAYS
Maximum availability
TRIAL
MONTH
FLEXIBLE PAYMENT
OPTIONS
1and1.com
CALL
SPEAK WITH AN
EXPERT 24/7
1 (877) 461-2631
*SSD offer and promotional pricing applies to the initial minimum contract term only and will renew at the regular rates. Visit www.1and1.com for full offer details, terms
and conditions. Dell, the Dell logo, the Dell badge and PowerEdge are trademarks of Dell Inc. Intel, the Intel Logo, Intel Inside, the Intel Inside logo, Intel. Experience
Whats Inside are trademarks of Intel Corporation in the U.S. and/or other countries. 1&1 and the 1&1 logo are trademarks of 1&1 Internet, all other trademarks are
property of their respective owners. 2015 1&1 Internet. All rights reserved.
Untitled-1 1
1and1.com
5/29/15 10:59 AM
Data Points
JULIE LERMAN
this:
using (var context = new AddressContext()) {
context.Address.Add(newAddress);
newAddress.Region=aRegionObjectFromDatabase;
}
and this:
newAddress.Region=aRegionObjectFromDatabase;
using (var context = new AddressContext()) {
context.Address.Add(newAddress);
}
20 msdn magazine
0715msdn_LermanDPts_v4_20-25.indd 20
6/8/15 2:33 PM
Untitled-3 1
4/6/15 2:41 PM
0715msdn_LermanDPts_v4_20-25.indd 22
Ill be doing my experiments against a particular model I already built in Visual Studio
using code first. I have one assembly with my
classesMonkey, Banana and Countryand
another assembly that contains a MonkeysContext that inherits from the EF DbContext
and exposes DbSets of Monkeys, Bananas and Countries. I verified
that my model was set up correctly using the View Entity Data
Model feature of the Entity Framework Power Tools extension
for Visual Studio (bit.ly/1K8qhkO). This way, I know I can depend on
the compiled assemblies Ill be using in my command-line tests.
In order to do these experiments, theres some common setup
I have to perform. I need references to my custom assemblies, as
well as to the EF assembly, and I need code that instantiates new
monkey, country and MonkeysContext objects.
Data Points
6/8/15 2:33 PM
ement1); areaSerie
areaSeries
ies.A
Add(seriesElement2);
A
dd(se
(s riesElement2
t2);
) areaSeries
areaSeries.Ad
Add(seriesElement3);
A d(seriesElement3); // Add series to the plot area plotArea
plotArea.Series.Add(areaSeries);
Series Add(areaSeries); //page
//page.Elemen
Elements
em ts.Add(
Add(
dd( new
ne LayoutGrid()
LayyoutGrid() ); /// Add
La
Add the page elements to the page AddEA
s, 240, 0); AddEAN1
AN 3Sup
Sup5(pa
5(p ge.Eleme
ent
nts, 480, 0); Ad
ddUPCVersionA(page.Elemen
e ts, 0, 135); AddUPCVersionASup2(page.Elements, 240, 135); Ad
dd
dUPC
UPC
CVers
sionA
o Sup5((page.Elemen
nts,
t 480, 135); AddEAN8(page.Elements, 0,
.Elements, 480, 270);; Add
ddU
UPCVersionE(pa
page.Elementts, 0, 405); AddUPCVersionESu
E p2(page.Elements, 240, 405); AddUPCVersionESup5(page
age.Ele
.Ele
lem
ments,
s, 48
480, 405); // Add the page
e tto the document document.Pages.Add(pa
CaptionAndRectang
a le
e(eleme
ements, EAN/JA
/JAN 13 Bar Cod
de, x, y, 204, 99); BarCode barCode = new Ean13(123456789012, x, y + 21); barCode.
ode.X
X+
+= (20
04 - ba
arCo
ode.GettSymbolWidth()
h ) / 2; elements.Add(barCode); } private vo
dRectangle(element
e s,, EAN
EAN/JAN 13 Bar
ar Code,
C
2 digit supplement, x, y, 204, 99); BarCode barCode = new Ean13Sup2(1
2 2345
56789
678 012
1212,
2, x, y + 21
21);
1); barCo
ode.X
X += (204 - barCode.GetSymbolWidth()) / 2; elements.Add((barC
ts, oat x, oat y) { AddCa
A CaptionAndRectan
angle(elements, EAN/JAN 13 Bar Code, 5 digit supplement, x, y, 204, 99); BarCo
a C de barCo
arC
Code
de = new
n
Ean13Su
Ean1
S p5(12
2345
567890
01212345, x, y + 21); barCode.X += (204 - barCode
e.Get
ddUPCVersionA(Grou
Group elemen
em ts, oat x, oat
oa y) { AddCaptionAndRectangle(element
e s, UPC Version A Bar Code, x, y, 204,
2
99);
9) Ba
B
BarrCode
C
barC
bar
Code = ne
ew UpcVe
pcVersionA
A(12345678901, x, y + 21); barCode.X += (204 - ba
arCo
ddUPCVersionAS
Sup2(
up2 Grou
oup
p elements,, oat
oa x, oat y) { AddCaptionAndRectangle(ele
( ments, UPC Version E Bar Code, 2 digit
git sup
supp
up lement
nt, x,
x y, 204, 99
9); Ba
arCod
de barC
Code = new UpcVersionASup2(12345678
7 90112, x,
x, y +
s.Add(barCode); } private
te vo
oid AddUPCV
PCVersi
ers onASup5(Group elements, oat x, oat
o y) { AddCaptionAndRectangle(ele
em
ment
ents, UPC
UPC Ver
Version E Bar Code, 5 dig
git su
upplem
ment, x, y, 204, 99); BarCode barCode = new UpcVe
ersio
ode.GetSymbolW
Width(
dth )) / 2
2; elements.Add
Add(bar
(ba Code); } private
e voi
v d AddEAN
EAN8(Group
p elements, oat x, oat y) { AddC
ddCapti
tionAn
onA
n dRec
Rec
ect
ctangle(elem
ments, EAN
N/JAN
N 8 Bar Cod
de, x, y, 204, 99); BarCode barCode = new
n
Ean8(1234
34
g(); leDialog.Title
le = Op
Open
en File
F Dialog
g; l
eDialog.Filter = Ad
Adobe PDF
F les
es (*.pdf)
f)|*.pdf|All Files (*.*)|*.*; if (leDi
eDialog.
log.Sh
Show
wDiallog()
og == Dialog
gResult.OK) { pdfViewe
ewer.Op
penFile(leDialog.FileName, ); } Save
Sav File
F Diallog sa
av
aveF
File Dialog; ssaveF
veFileDialo
al g.Filter = Ado
Adobe
e PDF les (*.pdf)
f)|*.pdf|All Files (**.*)|*.*; if (saveFileDialog.ShowD
owDialo
ialo
a g()=
g()==Dia
=Dia
Di logResul
esult
.O
OK) { pdfV
fViewe
ewerr.SaveAs(saveFileDia
Dialog.FileName
e); } if (p
( dfVi
dfV ewe
wer.P
Page
WithDialog(); } else
e se { Mess
Me ageBox.S
Show(
w P
Please open a le to printt); } OpenFile
F Dialog leDi
D alog
log = ne
ew Ope
penFileD
pen
Dialog(); le Dialog.Tiitle = Open File Dialo
og; lleDialog.InitialDirec
ecto
ory = @c:\
:\ ;
leD
leDialog
lo .Filter
ter = All
F
) == DialogResul
es t.O
t.OK) { Dy
D namicPDF
FView
ewerrClass test = new
ew Dynam
D
micPDFVie
ewerC
r lass(); PDF
DFPrin
Printter prin
inter
nter
er = test.OpenF
pe ileForP
orPrin
in
ntter
(leDia
(le
alog.FileName); prin
nter.PrintQuie
Quiet();
() } byt
by e[] cont
contents
t =
pServices; GCH
GC and
andle gc
ch = GCHandle
d .All
Al oc
c(contents, GCH
Hand
ndleTyp
Type.Pinned
d); Int
IntPtr cont
contents
entsIntPtr =gc
ch.
ch.
h.A
AddrOfPinned
nn Obje
ect()
ct ;p
pd
df
Viewer.O
.OpenB
pe ufffe
fer(co
r( ntentsIntPtr
t ,
ageElements,
s, oat
a x, oat
at y) { // Adds
dss a circltt to the pageElleme
ents AddCaptio
onAndR
AndRecta
ectangle(pag
pag
geEle
eEl ment
men s, Circle Page Elem
ment:
ent:,
t:: x,,
y); pageEl
geElements.A
s.Add(n
dd(new Circle(x
dd
(x + 112.5f
2 ,
shLarge)); } priva
vate
te void AddF
Ad or
ormatted
te
edTextArrea(Group
p page
geElemen
nts, oat x, oa
oatt y)
y { // A
Adds a fo
for
o mattted
d text area to
o thepageE
eElle ments strring formatt
m edHt
edHtml = <p><
<p <i>Dynamic</i><b>PD
b>P F</b
b>&tm
tm;
m Genera
era
ator
o v6.0 for
or
or .NE
matting suppo
ort for
or text th
that appearss in the document.
t. You
Y u havve + com
complet
ple
ete co
ontro
rol ovve
err 8 par
aragraph
ph properties:
p
spacing befo
efore
e, spacing
g after, r
rst liine + indenta
ntation, left indentati
tation, righ
r t in
ndent
ntatio
tion
n, aliignment, al
alllowi
<font face=Tim
Times
es>fontt fac
f e, </fon
nt>
><font poin
o tSiz
Size=6>ffont + size, </fon
</fon
nt><fo
<f ntt co
color
olo
llor=FF0000
00 >
>colo
or, </font>
><b>b
<b> old, </b
</b><
<i>italic and </i><
<u>u
underline</u>
>; + and 2 line pro
opert
rties: lea
eading
ng, an
nd le
ead
ding type. Text
extArea = ne
ew Format
Form tedT
dTextA
Area(for
orrmattedH
Htm
tml, x + 5, y + 20,, 215
5, 60,, F
Font
ontFamil
mi y.He
He
elvet
lv
vetica
e ica, 9, false)
e); // Sets the indent prope
roperty fo
formatte
att dTextAre
ea.Styyle.P
Paragrap
ph.In
ndent = 18; AddC
CapttionAndRect
Rectangl
gle(pa
e(pa
e
(pa
pa
ageE
geElements,
ts, F
ageEleme
m ntts, Fo
Form
mattedT
dTextA
tArea Overow
ow Text:, x + 279
9, y); pag
geEle
ement
men s.Ad
Add(fo
Ad
d(fo
d
ormat
orm
rmat
atttedTextA
tArea)); // Create
ea
an overow formatted
ed ttextt a
area forr the
t over
ow textt Fo
ormattedTextArea
a ove
overowFor
Formatt
ma edTe
Text
xtAr
tArea
ea = formatte
e
a(x + 284, y + 20);
20) p
pageE
Elemen
ements.Ad
dd(o
(over
verow
ow
wForm
wFo
rmat
a tedTe
extArea); } priv
private
ate void A
Add
dImag
mage(Group
mag
up pag
geElem
eme
ents, oat x, oat y) { /// Adds an
n image
e to th
he pa
ageElem
men
ents AddCaptionAndRe
dRectangle((pag
pageElem
ments
en
nts Image
nts,
ge
e Pag
es/DPDFLo
ogo.pn
.png), x + 112.5
5f, y + 50f,
50f, 0.24
0.24f
4f); // Image is size
ed an
nd cente
entered
d in
n the rec
ecta
tangle ima
m ge.SetBo
B unds(215, 60); image.VAlign = VAlign.Cen
enterr; ima
age.Align
n = Align.Center; pag
geE
eElements.Ad
.Add
d(imag
ge); } priv
vate void A
pageElemen
nts Ad
AddCap
dC tion
onAndRecta
angle(pag
ngle(pag
geElements,
eEle
L
Labell & PageNumbe
Page
eringL
erin
g bel Page E
gLab
Elem
ementts:, x, y); string labelText
T
= Labels can be rottated; strring number
mbe Text = PageNum
mbe
eringLabels
els cont
contai
ain page num
mb
be
ering
xt, x + 5, y + 12,
12 22
220, 80,
0 Fontt.Time
messRom
Roman,
an, 12, TextAlign..Cen
nter);; lab
label.Ang
Ang
gle = 8; Page
eNumb
Num erin
ri gLa
gLabel pageNumLabel = new PageNumber
b ingLabel
ab (n
numb
berText, x + 5, y + 55, 220, 80, Font.TimesR
esRoman, 12,
12 TextAl
tAlig
ign.
ign
n Ce
m nts.Add(labe
me
abel);
l); } private
e void AddL
dLin
ne(G p pageElemen
ne(Group
nts, oat x, oa
oat y)) { /// Addss a lin
ne to the
he pageE
pag lements AddCaptionAndRectangle(p
( ageEleme
e nts, Line Pa
age Element:, x, y); page
eElemen
nts.A
s.Add(ne
ew Line(x
x+5
5, y +
w Line(x
x + 220,
2
y + 20, x + 5, y + 80, 3,
3, RgbCo
Rg olor.Green)); } pr
priv
iva
ate void
d AddLi
A
ink
nk(Group
up p
pag
pa eElement
ments, oat x, oat y) { // Adds a link to the pageEleme
em ntts Fo
ont font = Fo
ont.TimesRoman;; st
string text = T
This iss a link
k to Dyna
amic
m :, x, y); Label label = ne
ment
new Lab
Label(textt, x + 5, y + 20, 215
5, 80
5,
0, fon
nt, 12, Rgb
R bColor.
or.B
Blu
lue);; label.Und
Under
erline = true; Link link = new Link(x + 5, y + 20, font.
on GetTe
extWidth
h(tex
xt, 12), 12 - font.G
GetD
Descend
der(1
r(12), ne
ew Url
UrlA
lAction(
n(h
http
E men
Ele
nts.Add(li
( nk);; } priva
p vate
e vvoid
d AddPath(
ath Grroup pageElem
mentts,
oat
oat x, oatt y) { // Ad
Adds a path
h to the pageElements ceTe.DynamicPDF.PageElement
en s.Path
h path = new
w ceTe.DynamicPD
PDF.P
F.PageElemen
men
nts.P
s.Pa
ath(
h(x
x + 5, y + 20,
2 R
P s.A
Path
Add(new Line
eSubPat
Pa h(x
x + 215, y + 40))); path.Su
h.S bPatths.A
Add
dd((new Curv
urve
eToSubPat
Pa h(x + 10
08, y + 80, x + 160, y + 80)); path.SubPaths.Add(new
w Curv
veSu
ubPath(x + 5, y + 40, x + 65,
6 y + 80, x + 5, y + 60))); Add
AddC
Ca ionA
Capt
And
Add(p
path); } private
e void AddR
Rec
ctangle(Gr
G oup
p page
eElemen
nts, oat
oat x, oat
at y)
y) ordere
e dLis
dL t = ord
deredList.GetOverFlowList(x + 5, y + 20); AddCaptionAn
AndR
Recta
ang
gle(pag
ge.Elements, Order
r ed List
L Page
ge
e Ele
El ment
nt Ove
Ove
v row
r :, x, y, 2
8; //
8;
// Create
C
an uno
ordere
ed list Unordered
nor e List unorder
e edList
er
stt = ne
ew Uno
norder
rderedL
edList(x
x + 5, y + 20,
20 400, 90, Font.Helvetica, 10); unorderedList.Items.Add(
Add(Fruits); unordered
ere List.Items.Add(
d Vege
Vege
g table
es); U
Unorde
r eredS
re
edS
d ub
bList unord
t();
(); unorderedSubList.Items.
ms.Add(
dd(( Citrus); unord
ordered
eredSu
edSubLiist.Ite
emss.Ad
Add
d( Non
n-Citr
t us)
s ; Ad
AddC
CaptionAndRectangle(page.Elemen
nts, Unordered Lis
st Page
e Elem
me
ent:, x, y,
y 225, 110); Uno
n rd
dere
edSubLis
bLis
st u
un
norde
deredS
redS
d ubLi
ub st2 = uno
erredSub
bList2.Items.Add((Po
Potato); unorderedS
SubLis
ubLiist2.Item
ms.Ad
dd(B
Beans); Unor
no dere
deredSub
dSubLisst subUnorderedSubList = unordered
e SubL
S
ist.Items[0]].Su
ubLists.A
AddUnorder
rde edSubList(); ssub
bUnor
UnorderedSub
dS
Sub
bList.Ite
te
ems.A
m Add
d(Lime); s
;<M<CFG<;=FI
@EKL@K@M<LJ<
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
Sub
List
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 ow:
ver
o , x, y, 225
oid
d Add
dTextField(Group pageElemen
dTextF
me ts,, o
oat x,, o
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
RgbC
Colo
or.B
r.Black; txt
xt ackgro
xt.Bac
kgroundC
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
men
nts, Tex
xtFi
Field Form
orm Pag
Page
e Elemen
Elemen
nt:,
:, x, yy,, 504
04, 85);
5) } priva
ate
e void
oid AddC
dComb
omb
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[
[NonNon-Edit
Editable
able].S
].Se
elected = true; cb1.
1 Edita
nts.Ad
nt
s
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
Zfdgfe\ekj#j`dgcpZfekXZkZ\K\Jf]knXi\ji\X[`cpXmX`cXYc\#`e[ljkip$c\X[`e^jlggfikk\Xd%
NNN%;PE8D@:G;=%:FD
KIPFLIG;=JFCLK@FEJ=I<<KF;8P
K
nnn%;peXd`ZG;=%Zfd&\mXcfiZXcc/''%-*(%,''-s"(+('%..)%/-)'
n
Untitled-1 1
9/8/11 12:41 PM
Back at the command prompt, Ill start the Scriptcs REPL with just
the scriptcs command and no parameters.
Once the REPL is active, the first thing I want it to do is load the
.csx file. Then Ill use the :references and :vars commands to verify
the REPL correctly ran the .csx file. (Scriptcs has a number of REPL
commands that start with a colon. You can see a list by typing :help.)
Figure 4 shows my session so far; you can see all of the APIs that
are referenced, as well as the objects I created.
I can also inspect the objects by just typing the variable name at
the prompt. Here, for example, is my monkey object:
> monkey
{
"Id": 0,
"Name": "scripting gal",
"Bananas": [],
"CountryOfOrigin": null,
"CountryOfOriginId": 1,
"State": 1
}
>
24 msdn magazine
0715msdn_LermanDPts_v4_20-25.indd 24
Data Points
6/8/15 2:33 PM
Figure 5, Ill have two rows for Indonesia. The fact that country
already had a key value (Id) will be ignored.
Next, Ill use the :reset command to clear the REPL history and
then #load the .csx again. After that, Ill try a new workflowadd
the monkey to the context and then attach the country to the monkey thats already being tracked. Note that Im not including all of
the responses in the following listing:
> :reset
> #load "SetupForMonkeyTests.csx"
> ctx.Monkeys.Add(monkey);
{...response...}
> monkey.CountryOfOrigin=country;
{...response...}
> ctx.Entry(monkey).State.ToString()
Added
> ctx.Entry(country).State.ToString()
Added
Again, the context assigns the Added state to the country object
because I attached it to another Added entity.
If you really want to use the navigation property, the pattern that
will give you success is to ensure that the context already is aware
of the country. This can happen either because youve retrieved the
country using a query in the same context instance, resulting in
the context assigning the Unchanged state to the object, or because
you manually assigned the Unchanged state yourself.
Figure 6 shows an example of the latter, which allows me to do
this testing without working with a database.
Because the context was already tracking the country, the country objects state wont be changed. EF only changes the state of the
related object when its state is unknown.
Thanks to the following Microsoft technical expert for reviewing this article:
Justin Rusbatch
msdnmagazine.com
0715msdn_LermanDPts_v4_20-25.indd 25
6/8/15 2:33 PM
Analyzing Architecture
with Code Maps in
Visual Studio 2015
Stuart Kent, Jean-Marc Prieur and Blair McGlashan
Improving the architecture of your application is crucial
Technologies discussed:
Visual Studio 2015, Microsoft .NET Framework, Code Map
We used two examples for illustration. For top-down architecture and drilling in, we used the Roslyn code base (the .NET
Compiler Platform). We chose this for two reasons. First, its large
26 msdn magazine
0715msdn_PrieurVS2015_v5_26-30.indd 26
6/8/15 2:24 PM
Finally, we built the solution (this can take some time). To get an
immediate understanding of the architecture of this code base, we
selected the Generate Code Map for Solution without Building
Understand Overall
Architecture
0715msdn_PrieurVS2015_v5_26-30.indd 27
6/8/15 2:24 PM
Analyze a Dependency
As you can clearly see in Figure 2, the Core inherits some classes
from CSharp and VisualBasic, which is a bit of a surprise. Lets
take a look at how to drill into this further to see whats causing the
anomaly. We started by selecting the dependency link (between
Core and CSharp) and choosing Show Contributing Links on New
Code Map. The result is shown in Figure 3.
We saw that one class is at fault, and had to wonder whether, in
fact, the VBCSCompiler.exe project/assembly should really be part
of the Core grouping. Perhaps we needed to refactor the Solution
Folder structure to move it out. But before making that change,
we used Code Map to explore the potential impact. Going back to
the map shown in Figure 2, we could re-enable all the link filters
in order to see all assemblies, and
edit the diagram by moving the
VBCSCompiler.exe node from
Core to CSharp, to see the impact
on dependencies (see Figure 4).
This certainly appeared to clean
things up, though we then found
that the Roslyn.Compilers.CompilerServer.UnitTests.dll also
seemed to be in the wrong place.
Exploration can continue in this
vein. You can even create new
group nodes on the diagram to
produce a cleaner architecture,
which can then be used to inform
0715msdn_PrieurVS2015_v5_26-30.indd 28
6/8/15 2:24 PM
0715msdn_PrieurVS2015_v5_26-30.indd 29
July 2015 29
6/8/15 2:24 PM
Wrapping Up
at Microsoft responsible for developer experiences in Visual Studio and Visual Studio
Online, focused on controlling technical
debt and code sharing and collaboration.
This includes architecture analysis tools,
aspects of CodeLens and code search.
0715msdn_PrieurVS2015_v5_26-30.indd 30
6/8/15 2:24 PM
Untitled-6 1
5/28/14 4:02 PM
C#
Brownfield Async
Development
Stephen Cleary
When the Visual Studio Async CTP came out, I was in a fortunate When to Use Async
position. I was the sole developer for two relatively small greenfield
applications that would benefit from async and await. During this
time, various members of the MSDN forums including myself were
discovering, discussing and implementing several asynchronous best
practices. The most important of those practices are compiled into my
March 2013 MSDN Magazine article, Best Practices in Asynchronous
Programming (msdn.microsoft.com/magazine/jj991977).
Applying async and await to an existing code base is a different
kind of challenge. Brownfield code can be messy, which further
complicates the scenario. A few techniques Ive found useful when
applying async to brownfield code Ill explain here. Introducing
async can actually affect the design in some cases. If theres any
refactoring necessary to separate the existing code into layers, I
recommend doing that before introducing async. For the purposes
of this article, Ill assume youre using an application architecture
similar to whats shown in Figure 1.
This article discusses:
Convert synchronous code to asynchronous
Resolving deadlocks in code operations
Applying hacks to get around code conflicts
Technologies discussed:
Visual Studio Async CTP, C#, Microsoft .NET Framework
The best general approach is to first think about what the application is actually doing. Async excels at I/O-bound operations, but
there are sometimes better options for other kinds of processing.
There are two somewhat common scenarios where async isnt a
perfect fitCPU-bound code and data streams.
If you have CPU-bound code, consider the Parallel class or Parallel
LINQ. Async is more suited to an event-based system, where theres
no actual code executing while an operation is in progress. CPUbound code within an async method will still run synchronously.
However, you can treat CPU-bound code as though it were asynchronous by awaiting the result of Task.Run. This is a good way to push
CPU-bound work off the UI thread. The following code is an example
of using Task.Run as a bridge between asynchronous and parallel code:
await Task.Run(() => Parallel.ForEach(...));
The other scenario where async isnt the best fit is when your application is dealing with data streams. Async operations have a definite
beginning and end. For example, a resource download starts when the
resource is requested. It finishes when the resource download completes.
If your incoming data is more of a stream or subscription, then async
may not be the best approach. Consider a device attached to a serial
port that may volunteer data at any time, as an example.
Its possible to use async/await with event streams. It will require
some system resources for buffering the data as it arrives until the
application reads the data. If your source is an event subscription,
consider using Reactive Extensions or TPL Dataflow. You might
32 msdn magazine
0715msdn_ClearyAsync_v4_32-40.indd 32
6/10/15 8:58 AM
Redmond
AUGUST 10 - 14
NAVIGATE THE
.NET HIGHWAY
CODE HOME
KEYNOTE AND
MICROSOFT SESSION
DETAILS
COMING SOON!
REGISTER BY
JULY 8 AND
SAVE $300
5 DAYS OF
EDUCATIONAL
SESSIONS AND
WORKSHOPS
EVENT SPONSOR
SUPPORTED BY
PRODUCED BY
magazine
0715msdn_VSLive_Insert.indd 1
vslive.com/redmond
6/1/15 1:13 PM
Redmond
AUGUST 10 - 14
Studio/.NET
Development
NAVIGATE THE
.NET HIGHWAY
REGISTER BY
JULY 8 AND
SAVE $300
Design
Mobile
Client
Windows
Client
Database
and Analytics
Cloud
Computing
Microsoft
Sessions
twitter.com/vslive @VSLive
facebook.com Search VSLive
linkedin.com Join the
Visual Studio Live group!
0715msdn_VSLive_Insert.indd 2
6/1/15 1:13 PM
find it a more natural fit than plain async. Both Rx and Dataflow
interoperate nicely with asynchronous code.
Async is certainly the best approach for quite a lot of code,
just not all of it. For the remainder of this article, Ill assume youve
considered the Task Parallel Library and Rx/Dataflow and have
concluded that async/await is the most appropriate approach.
The compiler guides you to the next step. Mark the method as
async and change the return type. If the return type of the synchronous method is void, then the return type of the asynchronous
Figure 2 Change All Calling Methods to Async
public interface IDataService
{
Task<string> GetAsync(int id);
}
public sealed class WebDataService : IDataService
{
public async Task<string> GetAsync(int id)
{
using (var client = new WebClient())
return await client.DownloadStringTaskAsync(
"http://www.example.com/api/values/" + id);
}
}
public sealed class BusinessLogic
{
private readonly IDataService _dataService;
public BusinessLogic(IDataService dataService)
{
_dataService = dataService;
}
msdnmagazine.com
0715msdn_ClearyAsync_v4_32-40.indd 33
July 2015 33
6/10/15 8:58 AM
Before moving on, check the rest of this method for any other
blocking or synchronous API calls that you can make async. Asynchronous methods shouldnt block, so this method should call
asynchronous APIs if theyre available. In this simple example,
Figure 3 Use Vertical Partitions to
Convert Sections of Code to Async
public interface IDataService
{
string Get(int id);
Task<string> GetAsync(int id);
}
public sealed class WebDataService : IDataService
{
public string Get(int id)
{
using (var client = new WebClient())
return client.DownloadString("http://www.example.com/api/values/" + id);
}
34 msdn magazine
0715msdn_ClearyAsync_v4_32-40.indd 34
Next, move to the calling methods and follow the same steps. You
should end up with something like the code in Figure 2. Unfortunately, code wont compile until all calling methods are transformed
to async, and then all of their calling methods are transformed to
async, and so on. This cascading nature of async is the burdensome
aspect of brownfield development.
Eventually, the level of asynchronous operation in your code
base will grow until it hits a method that isnt called by any other
methods in your code. Your top-level methods are called directly
by whichever framework youre using. Some frameworks such as
ASP.NET MVC permit asynchronous code directly. For example,
ASP.NET MVC controller actions can return Task or Task<T>.
Other frameworks such as Windows Presentation Foundation
(WPF) permit asynchronous event handlers. So, for example, a
button click event might be async void.
Performing an asynchronous
code transformation can be
scary the first few times, but it
really becomes second nature
after a bit of practice.
Hit the Wall
As the level of asynchronous code grows throughout your application, you might reach a point where it seems impossible to continue.
The most common examples of this are object-oriented constructs,
which dont mesh with the functional nature of asynchronous code.
Constructors, events and properties have their own challenges.
Rethinking the design is generally the best way around these
difficulties. One common example is constructors. In the synchronous code, a constructor method might block on I/O. In the
asynchronous world, one solution is to use an asynchronous factory
method instead of a constructor. Another example is properties.
If a property synchronously blocks on I/O, that property should
probably be a method. An asynchronous conversion exercise is
great at exposing these kinds of design issues that creep into your
code base over time.
C#
6/10/15 8:58 AM
Bo
os
Re AS
ad P
ou .N
r W ET
hit P
ep er
ap fo
er
on rm
lin an
e
ce
$) *+$"%&,-
.
!
" # $%%&
'
(
! )*#+ ,-
/0(*1
!"#$%&"'
Untitled-1 1
((("#$%&"'
5/12/15 11:28 AM
Transformation Tips
[TestMethod]
public void Get_RetrievesObject13()
{
AsyncContext.Run(() =>
{
var service = new WebDataService();
var result = service.Get(13);
Assert.AreEqual("frob", result);
});
}
36 msdn magazine
0715msdn_ClearyAsync_v4_32-40.indd 36
Vertical Partitions
The approach described so far works great if youre the only developer for your application, and you have no issues or requests that
would interfere with your asynchronous conversion work. Thats
not very realistic, though, is it?
If you dont have the time to convert your entire code base to be
asynchronous all at once, you can approach the conversion with a
slight modification called vertical partitions. Using this technique,
you can do your asynchronous conversion to certain sections
of code. Vertical partitions are ideal if youd like to just try out
asynchronous code.
To create a vertical partition, identify the user-level code youd
like to make asynchronous. Perhaps its the event handler for a
UI button that saves to a database (where youd like to keep the
UI responsive), or a heavily used ASP.NET request that does the
same (where youd like to reduce the resources required for that
specific request). Walk through the code, laying out the call tree
for that method. Then you can start at the low-level methods and
transform your way up the tree.
Other code will no doubt use those same low-level methods.
Because youre not ready to make all that code asynchronous, the
solution is to create a copy of the method. Then transform that copy
to be asynchronous. This way, the solution can still build at every
step. When youve worked your way up to the user-level code, youll
have created a vertical partition of asynchronous code within your
application. A vertical partition based on our example code would
appear as shown in Figure 3.
You may have noticed theres some code duplication with this
solution. All the logic for the synchronous and asynchronous
methods is duplicated, which isnt good. In a perfect world, code
duplication for this vertical partition is only temporary. The
duplicated code would exist only in your source control until the
application has been completely converted. At this point, you can
remove all old synchronous APIs.
However, you cant do this in all situations. If youre developing
a library (even one only used internally), backward compatibility
is a primary concern. You might find yourself needing to maintain
synchronous APIs for quite some time.
Figure 6 Use HttpClient with ConfigureAwait(false) to
Prevent Deadlock
public sealed class WebDataService : IDataService
{
public string Get(int id)
{
return GetAsync(id).GetAwaiter().GetResult();
}
C#
6/10/15 8:58 AM
Untitled-1 1
5/27/15 11:34 AM
The most straightforward approach is to simply block the asynchronous version. I recommend blocking with GetAwaiter().GetResult
instead of Wait or Result. Wait and Result will wrap any exceptions
within an AggregateException, which complicates error handling.
The sample service layer code would look like the code shown in
Figure 4 if it used the blocking hack.
Unfortunately, as the comment implies, that code wouldnt actually
work. It results in a common deadlock described in my Best Practices in Asynchronous Programming article I mentioned earlier.
This is where the hack can get tricky. A normal unit test will pass,
but the same code will deadlock if called from a UI or ASP.NET
context. If you use the blocking hack, you should write unit tests
that check this behavior. The code in Figure 5 uses the AsyncContext type from my AsyncEx library, which creates a context
similar to a UI or ASP.NET context.
The asynchronous unit test passes, but the synchronous unit test
never completes. This is the classic deadlock problem. The asynchronous code captures the current context and attempts to resume on
it, while the synchronous wrapper blocks a thread in that context,
preventing the asynchronous operation from completing.
In this case, our asynchronous code is missing a ConfigureAwait(false). However, the same problem can be caused by using WebClient.
WebClient uses the older event-based asynchronous pattern (EAP),
Figure 10 Apply Flag Argument Hack to Business Logic
public sealed class BusinessLogic
{
private readonly IDataService _dataService;
38 msdn magazine
0715msdn_ClearyAsync_v4_32-40.indd 38
C#
6/10/15 8:58 AM
which always captures the context. So even if your code uses ConfigureAwait(false), the same deadlock will occur from the WebClient code.
In this case, you can replace WebClient with the more async-friendly
HttpClient and get this to work on the desktop, as shown in Figure 6.
The blocking hack requires your team to have strict discipline.
They need to ensure ConfigureAwait(false) is used everywhere.
They must also require all dependent libraries to follow the same
discipline. In some cases, this just isnt possible. As of this writing,
even HttpClient captures the context on some platforms.
Another drawback to the blocking hack is
it requires you to use ConfigureAwait(false).
Its simply unsuitable if the asynchronous code
actually does need to resume on captured
context. If you do adopt the blocking hack,
youre strongly recommended to perform
unit tests using AsyncContext or another
similar single-threaded context to catch any
lurking deadlocks.
being blocked. On ASP.NET in particular, this approach will significantly reduce the applications ability to scale.
0715msdn_ClearyAsync_v4_32-40.indd 39
July 2015 39
6/10/15 8:58 AM
40 msdn magazine
0715msdn_ClearyAsync_v4_32-40.indd 40
This final hack is my least favorite. The idea is that you set up a nested
message loop within the UI thread and execute the asynchronous
code within that loop. This approach isnt an option on ASP.NET.
It may also require different code for various UI platforms. For
example, a WPF application could use nested dispatcher frames,
while a Windows Forms application could use DoEvents
within a loop. If the asynchronous methods dont depend on a
particular UI platform, you can also use AsyncContext to execute
a nested loop, as shown in Figure 12.
Dont be deceived by the simplicity of this example code. This
hack is the most dangerous of them all, because you must consider
reentrancy. This is particularly true if the code uses nested dispatcher frames or DoEvents. In that case, the entire UI layer must
now handle unexpected reentrancy. Reentrant-safe applications
require a considerable amount of careful thought and planning.
Wrapping Up
In an ideal world, you could perform a relatively simple code transformation from synchronous to asynchronous and everything would
be rainbows and unicorns. In the real world, its often necessary for
synchronous and asynchronous code to coexist. If you just want
to try out async, create a vertical partition (with code duplication)
until youre comfortable using async. If you must maintain the
synchronous code for backward-compatibility reasons, youll have
to live with the code duplication or apply one of the hacks.
Someday, asynchronous operations will only be represented with
asynchronous APIs. Until then, you have to live in the real world. I
hope these techniques will help you adopt async into your existing
applications in a way that works best for you.
n
S tephen C leary is a husband, father and programmer living in northern
Michigan. He has worked with multithreading and asynchronous programming
for 16 years and has used async support in the Microsoft .NET Framework since
the first CTP. Follow his projects and blog posts at stephencleary.com.
thankS to the following Microsoft technical experts for reviewing this article:
James McCaffery and Stephen Toub
C#
6/10/15 8:58 AM
INTRODUCING
Image-enabling experts & bacon connoisseurs. Visit us online to see our full line of SDKs for .NET, Java, and Mobile.
Untitled-1 1
www.atalasoft.com
4/7/15 10:53 AM
vslive.com/redmond
Redmond
AUGUST 10 - 14
CODE
HOME
No code trip would be complete
without a stop where it all began, so
were heading to the idyllic Microsoft
Headquarters in Redmond, WA,
August 10 14, 2015!
Join us as we explore hot topics like
Visual Studio, JavaScript/HTML5, ASP.NET,
Database and Analytics, and more in over
70+ sessions and workshops. Rub elbows
with Microsoft insiders, have lunch with
Blue Badges, visit the company store, and
experience code at the source.
EVENT SPONSOR
SUPPORTED BY
PRODUCED BY
vslive.com/redmond
magazine
Untitled-6 2
6/5/15 2:58 PM
NAVIGATE THE
.NET HIGHWAY
DEVELOPMENT
TRACKS INCLUDE:
Visual Studio/.NET
Web Development
Design
Mobile Client
Windows Client
Cloud Computing
Microsoft Sessions
REGISTER BY JULY 8
AND SAVE $300!
Scan the QR code to register
or for more event details.
vslive.com/redmond
March 16-20
June 1-4
June 15-18
August 10-14
Nov. 16-20
Untitled-6 3
6/5/15 2:59 PM
vslive.com/redmond
Redmond
AUGUST 10 - 14
AGENDA AT-A-GLANCE
Visual Studio Live!
has partnered with
the Hyatt Regency
Bellevue for conference
attendees at a special
reduced rate.
REGISTER
BY JULY 8
AND SAVE
$300!
Scan the QR code to register
or for more event details.
vslive.com/redmond
Cloud Computing
START TIME
END TIME
8:00 AM
12:00 PM
12:00 PM
2:30 PM
2:30 PM
6:00 PM
7:00 PM
9:00 PM
Dine-A-Round Dinner
START TIME
END TIME
8:30 AM
9:30 AM
9:45 AM
11:00 AM
11:15 AM
12:30 PM
12:30 PM
2:30 PM
2:30 PM
3:45 PM
3:45 PM
4:15 PM
4:15 PM
5:30 PM
M01 Workshop: Building Universal Apps for Desktop, Store, and Phone Philip Japikse
Lunch @ The Mixer Visit the Microsoft Company Store & Visitor Center
M01 Workshop Continues
5:30 PM
7:00 PM
START TIME
END TIME
8:00 AM
9:00 AM
9:15 AM
10:30 AM
10:45 AM
12:00 PM
W07 To Be Announced
12:00 PM
1:30 PM
1:30 PM
2:45 PM
2:45 PM
3:15 PM
3:15 PM
4:30 PM
8:00 PM
10:00 PM
START TIME
END TIME
8:00 AM
9:15 AM
9:30 AM
10:45 AM
11:00 AM
12:15 PM
TH11 To Be Announced
12:15 PM
2:15 PM
2:15 PM
3:30 PM
3:45 PM
5:00 PM
START TIME
END TIME
8:00 AM
12:00 PM
12:00 PM
1:00 PM
1:00 PM
5:00 PM
Lunch @ The Mixer Visit the Microsoft Company Store & Visitor Center
Untitled-6 4
6/5/15 2:59 PM
NAVIGATE THE
.NET HIGHWAY
Mobile Client
Web Development
Windows Client
Microsoft Sessions
M02 Workshop: UX Design Process Essentials Steps and Techniques Billy Hollis
M03 Workshop: ALM and DevOps with the Microsoft Stack Brian Randell
W13 To Be Announced
TH19 Microsofts .NET is Now Open Source and CrossPlatform. Why it Matters. Mark Rosenberg
F02 Workshop: Service Oriented Technologies: Designing, Developing, & Implementing WCF and the Web API Miguel Castro
vslive.com/redmond
Untitled-6 5
6/5/15 3:00 PM
G O O G L E A N A LY T I C S
Technologies discussed:
Microsoft Azure, Visual Studio 2015, Windows, Windows Phone,
Google Analytics
46 msdn magazine
0715msdn_DelfinoAnalytics_v5_46-50.indd 46
6/8/15 2:13 PM
To integrate an app, first you need to access the Google Analytics dashboard with a valid Google account, then create at least one application
account that can access the administrative area (bit.ly/1kPLnqG). Its also
a good idea to create separate application accounts for development,
beta testing and production. This way, you keep the data from each
set separate, and avoid polluting your important production data
with bad data from other developers and beta testers.
An application account uniquely identifies an application
(Contoso, for the purposes of this article). In this context, an application really refers to a collection of apps available for different
platforms and/or Web sites (Contoso for Windows, Contoso for
Android, Contoso Web dashboard), all of which send their telemetry information to the same account. Each application may
also be available in multiple versions (Contoso for Windows 1.0,
Contoso for Windows 1.1, Contoso for Android 2.0.1).
When you create the account in Google Analytics, you also need
to define one or more properties. Here, a property is an app or a
Web site for your account. An app property can have multiple versions, and its logical to have a property for each supported platform
(for example, ContosoW8, ContosoWP8, ContosoDroid). After
youve chosen names for your app and answered a few questions
to classify the business scope of the app, Google Analytics generates a numeric account ID and a tracking ID with the format
UA-xxxxxxxx-x, which represents your platform-specific app in
Google Analytics and will be used in all telemetry communications
sent from the app.
In my sample scenario, I have a universal application (W8.1 and
WP8.1), so I created two property IDs in one Google Analytics
account. To enable my app to talk with Google Analytics, Ill use a
NuGet package. To do this, for both the Windows and Windows
Phone apps, right-click on References, select manage NuGet packages, and add the package GoogleAnalyticsSDK. This package adds
a couple of references and the file analytics.xml, shown in Figure
1, to your Visual Studio solution. Youll have to edit this file so the
app can use the correct tracking ID you created earlier.
Finally, you must ensure your app is authorized to use the network.
For the Windows Phone app, select the ID_CAP_NETWORKING
capability in the WMAppManifest.xml file; for Windows 8, select
the Internet (client) capability in the package.appxmanifest file.
msdnmagazine.com
0715msdn_DelfinoAnalytics_v5_46-50.indd 47
Keep in mind that a view is not just an app page; you also need
to consider other aspects of the UI that focus the users attention
(such as the settings panel and dialog boxes) that you want to
monitor and analyze.
SendView requires a string parameter that uniquely identifies
the page or UI aspect youre tracking. This name will appear on
the Google Analytics dashboard and on reports as the reference
for your page. It should be generic and meaningful and easily associable with the source page. It must not be translated even if your
app supports multiple languages because it would be interpreted
by the analysis system as a different page. In other words, unless
you specifically want to differentiate telemetry data for localized
versions of your app, make sure the identifiers you send to Google
Analytics are not themselves localized.
Now the app is ready to send its first page-navigation telemetry
information. To see it, open your app and navigate through the pages
for a while.
July 2015 47
6/8/15 2:13 PM
0715msdn_DelfinoAnalytics_v5_46-50.indd 48
6/8/15 2:13 PM
0715msdn_DelfinoAnalytics_v5_46-50.indd 49
Ive discovered that 55 percent of users dont send their data to the
cloud, so in order to get a precise profile of my users, at the end of
each GPS activity the app sends one event with information about
the distance covered, and one event with the total elapsed time of
the activity, using code similar to the following:
Figure 5 Sample Events
Group
Action
Label
Value
Grp1
Press
Button1
Grp1
Press
Button1
Grp1
Press
Button1
Grp1
Press
Button2
Grp1
Tap
Label1
Unique Events
Event value
12
2.4
July 2015 49
6/8/15 2:13 PM
As a result, Ive obtained the data shown in Figure 7 for the first
week of February 2015.
What this analysis says is: In the first week of February, the app
has successfully tracked more than 15,000 hours (54,000,000
seconds) and 51,000 Km (32,000 miles). The average user uses the
app for an activity of about 5 Km (3.1 miles), covering the distance
in an hour and a half (5,400 seconds).
Good to know, but not enough! This is just an average usage
view, but more likely youd want to know how that usage is really
distributed. This is a multisport app, so youd want to know the
most popular sport and whether that popularity comes from a
small number of users using the app often or a lot of users using
it, but for only a short amount of time.
This is where Google Analytics custom dimensions and metrics
can help. Custom dimensions and metrics allow you to bring
additional data into Google Analytics that can help you answer
new questions about how users are interacting with your content.
A metric is a count of a data type thats summed up across your
Google Analytics hits. A metric corresponds to a column in a
report. Dimensions allow you to break down a metric by a particular value, for example, screen views by screen name. Dimensions
correspond to the rows in a report (bit.ly/1lOry2r).
There are two main steps to implement a custom dimension or metric:
Define the custom dimension or metric using the Google
Analytics Web interface (bit.ly/1Je9RJQ).
Implement code to set and collect custom dimension and
metric values.
Each Google Analytics property has 20 available indices for
custom dimensions, and another 20 indices for custom metrics.
Once a dimension or a metric is created, your code can refer to that
metric or dimension using the corresponding index.
Getting back to my question, to understand the sport breakdown
I created a Dimension, Activity Type, with scope, Hit, and used the
following code to track this information on the view shown by the
app during a fitness session:
GoogleAnalytics.EasyTracker.GetTracker().SetCustomDimension(1, activityType);
GoogleAnalytics.EasyTracker.GetTracker().SendView("Running");
A/B Testing
0715msdn_DelfinoAnalytics_v5_46-50.indd 50
You can track the success of the layout by recording the button
click using:
GoogleAnalytics.EasyTracker.GetTracker().SendEvent(
"ABTest", "Scenario1", "pageV1", 0);
Wrapping up
Italian services division and the author of Caledos Runner, one of most successful
fitness-tracking apps for Windows Phone, which gave him the opportunity to use
telemetry to discover and analyze how people use his app. You can reach him at
[email protected] or [email protected].
ThaNks to the following Microsoft technical expert for reviewing this article:
Kraig Brockschmidt
Google Analytics
6/8/15 2:13 PM
Untitled-1 1
4/1/14 10:47 AM
VSLIVE.COM/NEWYORK
New York
SEPTEMBER 28
OCTOBER 1
THE CODE
THAT NEVER
SLEEPS
Visual Studio Live! is
hitting the open road on
the ultimate code trip
to help you navigate the
.NET Highway. The next
stop? NYC, and were
geared up to be back in
the big apple for the first
time in 2012.
From September 28
October 1, Visual Studio
Live! is bringing its
unique brand of practical,
unbiased, Developer
training to Brooklyn,
offering four days of
sessions, workshops
and networking events
all designed to help
you avoid road blocks
and cruise through your
projects with ease.
GOLD SPONSOR
SUPPORTED BY
PRODUCED BY
magazine
Untitled-8 2
6/1/15 2:43 PM
NAVIGATE THE
.NET HIGHWAY
DEVELOPMENT
TOPICS INCLUDE:
VISUAL STUDIO / .NET
WEB DEVELOPMENT
DESIGN
MOBILE CLIENT
WINDOWS CLIENT
DATABASE AND
ANALYTICS
CLOUD COMPUTING
Register by August 5
and Save $300!
USE PROMO CODE NYJUL4
SCAN THE QR CODE TO REGISTER
OR FOR MORE EVENT DETAILS.
VSLIVE.COM/NEWYORK
March 16-20
June 1-4
June 15-18
Nov. 16-20
Untitled-8 3
6/1/15 2:42 PM
VSLIVE.COM/NEWYORK
New York
SEPTEMBER 28
OCTOBER 1
Mary Jo Foley,
Journalist and
Author
Register by August 5
and Save $300!
USE PROMO CODE
VSLJUL4
SCAN THE QR CODE TO REGISTER
OR FOR MORE EVENT DETAILS.
VSLIVE.COM/NEWYORK
FOLLOW US
twitter.com/vslive @VSLive
Untitled-8 4
6/1/15 2:57 PM
Cloud Computing
START TIME
6:00 PM
6:45 PM
9:00 PM
Mobile Client
Web Development
Windows Client
Visual Studio Live! Pre-Conference Workshops: Monday, September 28, 2015 (Separate entry fee required)
END TIME
9:00 AM
Design
Dine-A-Round
START TIME
END TIME
8:00 AM
9:00 AM
9:15 AM
10:30 AM
10:45 AM
12:00 PM
12:00 PM
1:30 PM
1:30 PM
2:45 PM
3:00 PM
4:15 PM
4:15 PM
5:30 PM
Welcome Reception
START TIME
END TIME
8:00 AM
9:00 AM
9:15 AM
10:30 AM
10:45 AM
12:00 PM
12:00 PM
1:30 PM
1:30 PM
2:45 PM
W10 - To Be Announced
3:00 PM
4:15 PM
4:30 PM
5:45 PM
7:00 PM
9:00 PM
START TIME
END TIME
8:00 AM
9:15 AM
9:30 AM
10:45 AM
11:00 AM
12:15 PM
TH09 - To Be Announced
12:15 PM
1:30 PM
Lunch
1:30 PM
2:45 PM
3:00 PM
4:15 PM
vslive.com/newyork
Untitled-8 5
VSL_NY15_4pg_ad_July_final.indd
5
6/1/15 2:43
5/29/15
1:15 PM
AZURE INSIDER
Technologies discussed:
Microsoft Azure, ASP.NET Web API, Node.js, Raspberry Pi,
Internet of Things
56 msdn magazine
0715msdn_TerkAzure_v3_56-60.indd 56
6/8/15 2:26 PM
One of the really useful features at the new portal is the ability
to query and view the actual data in DocumentDB, allowing you
to see the city and temperature data in its native JSON format. This
dramatically simplifies your ability to easily alter the Node.js Web
server and to build out any necessary queries.
From there, youll need two pieces of information. The first is the
URI to the DocumentDB data store. The second is the information security key (called the Primary Key at the portal), which lets
you enforce secure access from the Node.js Web server. Youll see
the connection and database information in the following code:
{
"HOST"
"AUTH_KEY"
"DATABASE"
"COLLECTION"
:
:
:
:
"https://temperaturedb.documents.azure.com:443/",
"secret key from the portal",
"TemperatureDB",
"CityTempCollection"
msdnmagazine.com
0715msdn_TerkAzure_v3_56-60.indd 57
};
// +-----------------------------+
// |
Section 6
|
// +-----------------------------+
// If the collection does not exist for the database provided, create it,
// or return the collection object. As with readOrCreateDatabase, this method
// first tried to find a collection with the supplied identifier. If one exists,
// it is returned and if one does not exist it is created for you.
var readOrCreateCollection = function (database, callback) {
client.queryCollections(database._self, 'SELECT * FROM root r WHERE r.id="' +
collectionId + '"').toArray(function (err, results) {
console.log('readOrCreateCollection');
if (err) {
// Some error occured, rethrow up
throw (err);
}
if (!err && results.length === 0) {
// No error occured, but there were no results returned, indicating no
// collection exists in the provided database matching the query.
client.createCollection(database._self, { id: collectionId },
function (err, createdCollection) {
console.log('client.createCollection');
callback(createdCollection);
});
} else {
// Found a collection
console.log('found a collection');
callback(results[0]);
}
});
};
// +-----------------------------+
// |
Section 7
|
// +-----------------------------+
// Query the provided collection for all non-complete items.
// Use queryDocuments to look for all documents in the collection that are
// not yet complete, or where completed = false. It uses the DocumentDB query
// grammar, which is based on ANSI - SQL to demonstrate this familiar, yet
// powerful querying capability.
var listItems = function (collection, callback) {
client.queryDocuments(collection._self, 'SELECT c.City,
c.Temperatures FROM c where c.id="WACO- TX"').toArray(function (err, docs) {
console.log('called listItems');
if (err) {
throw (err);
}
callback(docs);
});
July 2015 57
6/8/15 2:26 PM
In previous articles, the temperature database was named TemperatureDB. Each database can have multiple collections, but in this case
theres just one called the CityTemperature collection. A collection is
nothing more than a list of documents. In this data model, a single
document is a city with 12 months of temperature data.
As you dive into the details of the code for the Node.js Web server,
you can take advantage of the extensive ecosystem of add-on libraries for Node.js. Youll use two libraries (called Node Packages) for
this project. The first package is for DocumentDB functionality.
The command to install the DocumentDB package is: npm install
documentdb. The second package is for reading the configuration
file: npm install nconf. These packages provide additional capabilities missing in the default installation of Node.js. You can find a
more extensive tutorial about building out a Node.js application
for DocumentDB in the Azure documentation at bit.ly/1E7j5Wg.
There are seven sections in the Node.js Web server, as shown
in Figure 1. Section 1 covers connections to some of the installed
packages so youll have access to them later in the code. Section
1 also defines the default port to which the mobile client will
connect. When deployed to Azure, the port number is managed
by Azure, hence the process.env.port construct.
Section 2 reads from the config.json file, which contains the connection information, including the database and document collection.
It always makes sense to take string literals relating to connection
information and place them separately in a configuration file.
Section 3 is the client connection object youll use to interact
with DocumentDB. The connection is passed to the constructor
for DocumentDBClient.
Section 4 represents the code executed once the mobile client
connects to the Node.js Web Server application. The createServer
is a core primitive for Node.JS applications, and involves a number
of concepts around the event loop and processing HTTP requests.
You can read more about that construct (bit.ly/1FcNq1E).
This represents the high-level entry point for clients connecting
to the Node.js Web server. Its also responsible for calling other
pieces of Node.js code that retrieves JSON data from DocumentDB.
Once the data is retrieved, it will package it as a JSON-based
payload, and deliver it to a mobile client. It leverages the request
and response objects, which are parameters to the createServer
function, (http.createServer(function (req, res)...).
Section 5 begins the DocumentDB query processing. Your
DocumentDB data store can contain multiple databases. The purpose
of Section 5 is to narrow down the data at the DocumentDB URI and
point to a specific database. In this case, thats TemperatureDB. Youll
also see some extra code that isn't directly used, but is there purely for
educational purposes. Youll also notice some code to create a database if one does not exist. Much of the logic in Section 5 and beyond
is based on the DocumentDB npm package installed earlier.
Section 6 represents the next step in the data retrieval process.
The code here is automatically called as a result of the code in
Section 5. Section 6 further narrows the data, drilling down to the
document collection using the database established (TemperatureDB) in Section 5. Youll note the select statement that includes a
where clause for the CityTemperature collection. That includes
some code to create a collection if one does not exist.
58 msdn magazine
0715msdn_TerkAzure_v3_56-60.indd 58
Azure Insider
6/8/15 2:26 PM
Untitled-2 1
5/31/13 10:57 AM
Wrapping Up
This concludes the three-part series, where I set out to show an endto-end IoT scenariofrom data ingestion to persisting the data to
visualizing the data. I started this series by ingesting the data using a C
60 msdn magazine
0715msdn_TerkAzure_v3_56-60.indd 60
}
catch (WebException e)
{
return;
}
}
// +-----------------------------+
// |
Section 5
|
// +-----------------------------+
// Data structures coming back from Node
public class CityTemp
{
public string City { get; set; }
public List<double> Temperatures { get; set; }
}
// Data structure suitable for the chart control on the phone
public class NameValueItem
{
public string Name { get; set; }
public double Value { get; set; }
}
Thanks to the following Microsoft technical experts for reviewing this article:
Leland Holmquest, David Magnotti and Nick Trogh
Azure Insider
6/8/15 2:26 PM
Clean Data
Made Easy
One of the most important steps to ensuring business success is to keep your
database clean. We have easy-to-integrate data quality tools to do just that.
www.MelissaData.com/easy
Germany
www.MelissaData.de
India
www.MelissaData.in
United Kingdom
www.MelissaData.co.uk
Australia
www.MelissaData.com.au
Untitled-4 1
www.MelissaData.com
1-800-MELISSA
6/8/15 12:10 PM
Untitled-1 2
6/9/15 12:41 PM
Untitled-1 3
6/9/15 12:41 PM
C++
Technologies discussed:
C++, Standard Template Library, Visual Studio, Win32 API
64 msdn magazine
0715msdn_DicannioStrings_v3_64-68.indd 64
6/8/15 2:31 PM
0715msdn_DicannioStrings_v3_64-68.indd 65
stored in STL string classes. At this point, you need to pass those
STL strings across Win32 API boundaries (which expose a pure-C
interface, as discussed in the beginning of this article). With ATL,
WTL and MFC, the framework implements the glue code between
the Win32 C interface layer and CString, hiding it under the hood,
but this convenience isnt available with STL strings.
For the purpose of this article, lets assume the strings are stored
in Unicode UTF-16 format, which is the default Unicode encoding
for Windows APIs. In fact, if those strings used another format
(such as Unicode UTF-8), those could be converted to UTF-16 at the
Win32 API boundary, satisfying the aforementioned requirement
of this article. For these conversions, the Win32 MultiByteToWideChar and WideCharToMultiByte functions could be used: The
former can be called to convert from a Unicode UTF-8-encoded
(multi-byte) string to a Unicode UTF-16 (wide) string; the latter
can be used for the opposite conversion.
In Visual C++, the std::wstring type is well-suited to represent
a Unicode UTF-16 string, because its underlying character type is
wchar_t, which has a size of 16 bits in Visual C++, the exact size of
a UTF-16 code unit. Note that on other platforms, such as GCC
Linux, a wchar_t is 32 bits, so a std::wstring on those platforms would
be well-suited to represent Unicode UTF-32-encoded text. To
remove this ambiguity, a new standard string type was introduced in
C++11: std::u16string. This is a specialization of the std::basic_string
class with elements of type char16_t, that is, 16-bit character units.
If a Win32 API expects a PCWSTR (or LPCWSTR in older terminology), that is, a const wchar_t* NUL-terminated C-style input
string parameter, simply calling the std::wstring::c_str method will
be just fine. In fact, this method returns a pointer to a read-only
NUL-terminated C-style string.
Note that, while the ATL/MFC CString offers an implicit conversion to a raw character const pointer (const TCHAR*, which
is equivalent to const wchar_t* in modern Unicode builds), STL
strings do not offer such an implicit conversion. Instead, you must
make an explicit call to the STL strings c_str method. Theres a
common understanding in modern C++ that implicit conversions
July 2015 65
6/8/15 2:31 PM
Or, using std::make_unique (available since C++14 and implemented in Visual Studio 2013):
auto buffer = std::make_unique< wchar_t[] >(bufferLength);
Then, once a buffer of proper size is allocated and ready for use, the
GetWindowText API can be called, passing a pointer to that string
buffer. To get a pointer to the beginning of the raw buffer managed
by the std::vector, the std::vector::data method (bit.ly/1I3ytEA) can be
used, like so:
// Get the text of the specified control
::GetWindowText(hWnd, buffer.data(), bufferLength);
Note that this is simpler than using a raw new wchar_t[bufferLength] call, because that would require properly releasing the
buffer with a call to delete[] (and forgetting to do that would cause
a memory leak). Using std::vector is just simpler, even if using
vector has a small overhead compared to a raw new[] call. In fact,
in that case the std::vectors destructor would automatically delete
the allocated buffer.
This also helps in building exception-safe C++ code: If an exception
is thrown somewhere in the code, the std::vector destructor would be
automatically called. Instead, a buffer dynamically allocated with new[],
whose pointer is stored in a raw owning pointer, would be leaked.
Another option, considered as an alternative to std::vector, might be
the use of std::unique_ptr, in particular, std::unique_ptr< wchar_t[]
>. This option has the automatic destruction (and exception-safety)
of std::vector (thanks to std::unique_ptrs destructor), as well as less
overhead than std::vector, because std::unique_ptr is a very tiny
C++ wrapper around a raw owning pointer. Basically, unique_ptr
66 msdn magazine
0715msdn_DicannioStrings_v3_64-68.indd 66
And, finally, the text of the control can be deep copied from the
temporary buffer into a std::wstring instance:
std::wstring text(buffer.data()); // When buffer is a std::vector<wchar_t>
std::wstring text(buffer.get()); // When buffer is a std::unique_ptr<wchar_t[]>
if (error != ERROR_SUCCESS)
{
// Some error occurred
// Handle it e.g. throwing an exception
}
// All right!
// Continue processing
// Build a std::wstring with the NUL-terminated text
// previously stored in the buffer
std::wstring text(buffer.get());
C++
6/8/15 2:31 PM
Simplify
Reveal
Search
Exception Trail
Compare
Quick Actions
Trace
Get an exclusive
DISCOUNT
oz-code.com | [email protected]
Untitled-1 1
4/6/15 4:01 PM
A C++ programmer might be tempted to use the std::wstring::data method to access the internal string content, via a pointer to
be passed to the GetWindowText call. But wstring::data returns a
const pointer, which wouldnt allow the content of the internal string
buffer to be modified. And because GetWindowText expects write
access to the content of the wstring, that call wouldnt compile. So,
an alternative is to use the &text[0] syntax to get the address of the
beginning of the internal string buffer, to be passed as an output
(that is, modifiable) string to the desired Win32 API.
Compared to the previous approach, this technique is more efficient
because theres no temporary std::vector, with a buffer first allocated,
then deep copied into a std::wstring and, finally, discarded. In fact,
in this case, the code just operates in place in a std::wstring instance.
Avoiding Bogus Double-NUL-Terminated Strings Pay attention to the last line of code in Figure 1:
// Resize down the string to avoid bogus double-NUL-terminated strings
text.resize(bufferLength - 1);
0715msdn_DicannioStrings_v3_64-68.indd 68
The race condition that could arise in this case is another process
modifying the string value between the two RegQueryValueEx calls.
The string length returned by the first call could be a meaningless
value, unrelated to the new string value written in the Registry by
the other process. So, the second call to RegQueryValueEx would
read the new string in a buffer allocated with a wrong size.
To fix that bug, you can use a coding pattern like the one in Figure 2.
The use of the while loop in Figure 2 ensures that the string
is read in a buffer of proper length, because each time ERROR_
MORE_DATA is returned, a new buffer is allocated with the
proper bufferLength value until the API call succeeds (returning
ERROR_SUCCESS) or fails for a reason other than providing an
insufficiently sized buffer.
Wrapping Up
OS, a Pluralsight author and a Visual C++ MVP. Besides programming and
course authoring, he enjoys helping others on forums and communities devoted
to C++, and can be contacted at [email protected].
C++
6/8/15 2:31 PM
TechMentor 2016 WILL NOT be returning to Redmond DONT MISS this unique opportunity!
microsoft headquarters,
redmond, wa
august 3 - 7, 2015
engineered
for you
@ the source
Join us August 3 7, 2015 for TechMentor 2015:
Datacenter Edition, focused entirely on making your datacenter
more modern, capable, and manageable through 5 days of
immediately usable IT education.
the agenda
features:
75-minute topic overview
breakout sessions
3 hour content-rich deep dives
"Hands on" labs with your
own laptop
content areas
include:
Windows PowerShell
SESS I ON S A R E F I L L I N G
U P QU I C K LY
Infrastructure Foundations
Runbook Automation
REGISTER
TODAY!
U SE PROMO C ODE
event sponsor:
TM J U L1
platinum sponsor:
Configuration and
Service Management
Scan the QR code to register
or for more event details.
gold sponsors:
TECHMENTOREVENTS.COM/REDMOND
Untitled-3 1
Datacenter Provisioning
and Deployment
supported by:
produced by:
6/8/15 11:29 AM
R PROGRAMMING L ANGUAGE
Introduction to R for C#
Programmers
James McCaffrey
The R language is used by data scientists and programmers for statistical computing. In part because of the increasing
amounts of data collected by software systems, and the need to
analyze that data, R is one of the fastest-growing technologies among
my colleagues who use C#. A familiarity with R can be a valuable
addition to your technical skill set.
The R language is a GNU project and is free software. R was
derived from a language called S (for statistics), which was
created at Bell Laboratories in the 1970s. There are many excellent
online tutorials for R, but most of those tutorials assume youre a
university student studying statistics. This article is aimed at helping
C# programmers get up to speed with R as quickly as possible.
The best way to see where this article is headed is to take a look
at the example R session in Figure 1. The example session has two
unrelated topics. The first few set of commands show whats called
a chi-square test (also called the chi-squared test) for a uniform
distribution. The second set of commands shows an example of
linear regression, which in my opinion is the Hello World technique of statistical computing.
The R Web site is located at r-project.org. The site has links to several mirror sites where you can download and install R. The install
is a simple self-extracting executable. R is officially supported on
Windows XP and later, and also on most common non-Windows
platforms. Ive installed R on Windows 7 and Windows 8 machines
This creates a vector named observed using the c (for concatenate) function. A vector holds objects with the same data type. A
roughly equivalent C# statement would be:
var observed = new int[] { 20, 28, 12, 32, 22, 36 };
Technologies discussed:
R, C#, Visual Studio
In R, the dot (.) character is often used rather than the underscore
(_) character to create variable and function names that are easier to
read. The result of calling the chisq.test function is quite a bit of text:
Chi-squared test for given probabilities
data: observed
X-squared = 15.28, df = 5, p-value = 0.009231
70 msdn magazine
0715msdn_McCaffreyR_v5_70-75.indd 70
6/8/15 2:21 PM
0715msdn_McCaffreyR_v5_70-75.indd 71
> setwd("C:\\IntroToR")
> data <- read.table("DummyData.txt",
header=TRUE, sep=",")
> print(data)
The first command sets the working directory so I wouldnt have to fully qualify the path to the source data
file. Instead of using the (\\) token as is common with C#, I could
have used (/) as is common on non-Windows platforms.
The second command loads the data into memory in a table
object named data. Notice that R uses named parameters. The
header parameter tells if the first line is header information (TRUE,
or T in shortened form) or not (FALSE or F). R is case-sensitive
and you can usually use either the (<-) operator to assign values,
or the (=) operator. The choice is mostly a matter of personal
preference. I typically use (<-) for object assignment and (=) for
parameter value assignment.
The sep (separator) parameter indicates how values on each
line are separated. For example, (\t) would indicate tab-delimited
values, and (" ") would indicate space-delimited values.
The print function displays the data table in memory. The print
function has many optional parameters. Notice that the output in
Figure 1 displays data item indices starting at 1. For array, matrix
and object indices, R is a 1-based language, rather than 0-based
like the C# language.
July 2015 71
6/8/15 2:21 PM
You can interpret the first command as, Store into an object named
model the result of the lm (linear model) function analysis where the
dependent variable to predict is the Rate column in the table object
(data$Rate), and the independent predictor variables are Color, Length
and Width. The second command means, Display just the basic
results of the analysis stored in the object named model.
The lm function generates a large amount of information. Suppose
you wanted to predict the Rate value when the input values are Color
= pink, Length = 5.0 and Width = 1.9. (Notice that this corresponds
to data item [4], which has an actual Rate value of 0.4.) To make a
prediction youd use the values in the Estimate column:
Coefficients:
(Intercept)
data$Colorpink
data$Colorteal
data$Length
data$Width
Notice the predicted Rate, 0.43, is quite close to the actual rate, 0.40.
In words, to make a prediction using the model, you calculate a
linear sum of products of the Estimate values multiplied by their
corresponding X values. The Intercept value is a constant not
associated with any variable. When you have categorical explanatory variables, one of the values is dropped (blue in this case).
The information at the bottom of the output display indicates
how well the independent variables, Color, Length and Width,
explain the dependent variable, Rate:
Residual standard error: 0.05179 on 3 degrees of freedom
Multiple R-squared: 0.9927,
Adjusted R-squared: 0.9829
F-statistic: 101.6 on 4 and 3 DF, p-value: 0.00156
The multiple R-squared value (0.9927) is the percentage of variation in the dependent variable explained by the linear combination
of the independent variables. Put slightly differently, R-squared is a
value between 0 and 1 where higher values mean a better predictive
model. Here, the R-squared value is extremely high, indicating Color,
Length and Width can predict Rate very accurately. The F-statistic,
adjusted R-squared value, and p-value are other measures of model fit.
One of the points of this example is that when programming
using R, your biggest challenge by far is understanding the statistics behind the language functions. Most people learn R in an
incremental way, by adding knowledge of one technique at a
time, as needed to answer some specific question. A C# analogy
would be learning about the various collection objects in the
Figure 2 Contingency Matrix
Male
Female
Dem
Rep
Other
15
25
10
50
30
15
50
45
40
15
100
72 msdn magazine
0715msdn_McCaffreyR_v5_70-75.indd 72
The p-value result of the test is 0.01022, which indicates that at the
5 percent significance level, the two factors are not independent. In
other words, theres a statistical relationship between sex and affiliation.
Notice in the first chi-square dice example, the input parameter is a
vector, but in the second sex-affiliation example, the input is a matrix.
The chisq.test function has a total of seven parameters, one required
(a vector or a matrix), followed by six optional named parameters.
Like many C# methods in the Microsoft .NET Framework namespaces, most R functions are heavily overloaded. In C#, overloading
is usually implemented using multiple methods with the same
name but with different parameters. The use of generics is also
a form of overloading. In R, overloading is implemented using a
single function with many optional named parameters.
Graphs with R
6/8/15 2:21 PM
The nrow and ncol functions return the number of rows or the
number of columns in their matrix argument. Here, both values
would be 25.
The next R command uses the colorRampPalette function to
create a custom color gradient palette to paint the graph:
> jet.colors <- colorRampPalette(c("midnightblue", "blue",
+ "cyan", "green", "yellow", "orange", "red", "darkred"))
When typing a long line in R, if you hit the <Enter> key, the system
will jump the cursor down to the next line and place a + character
as a prompt to indicate your command is not yet complete. Next:
> nbcol <- 64
> color <- jet.colors(nbcol)
If you look closely at the graph in Figure 3, youll see the surface
is made of 25 x 25 = 625 small squares, or facets. The two preceding
commands create a 25 x 25 matrix where the value in each cell is one
of the 64 colors to use for the corresponding surface facet.
Finally, the 3D graph is displayed using the persp (perspective
graph) function:
0715msdn_McCaffreyR_v5_70-75.indd 73
6/8/15 2:21 PM
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Console.ReadLine();
}
} // Main
static void ShowVector(int[] v)
{
for (int i = 0; i < v.Length; ++i)
Console.Write(v[i] + " ");
Console.WriteLine("");
}
0715msdn_McCaffreyR_v5_70-75.indd 74
return p;
a =
y =
s =
z =
e =
c;
chi-square (X-squared in the R output), and method ChiSquareProb uses the return from ChiSquareStatistic to compute a probability (the p-value in the R output).
Method ChiSquareStatistic is a simple test for uniform distribution.
The statistics equation for the chi-squared statistic is:
chi-squared = Sum( (observed - expected)^2 / expected )
6/8/15 2:21 PM
A Few Comments
0715msdn_McCaffreyR_v5_70-75.indd 75
}
public static double Gauss(double z)
{
// input = z-value (-inf to +inf)
// output = p under Normal curve from -inf to z
// e.g., if z = 0.0, function returns 0.5000
// ACM Algorithm #209
double y; // 209 scratch variable
double p; // result. called 'z' in 209
double w; // 209 scratch variable
if (z == 0.0)
p = 0.0;
else
{
y = Math.Abs(z) / 2;
if (y >= 3.0)
{
p = 1.0;
}
else if (y < 1.0)
{
w = y * y;
p = ((((((((0.000124818987 * w
- 0.001075204047) * w + 0.005198775019)
- 0.019198292004) * w + 0.059054035642)
- 0.151968751364) * w + 0.319152932694)
- 0.531923007300) * w + 0.797884560593)
}
else
{
y = y - 2.0;
p = (((((((((((((-0.000045255659 * y
+ 0.000152529290) * y - 0.000019538132)
- 0.000676904986) * y + 0.001390604284)
- 0.000794620820) * y - 0.002034254874)
+ 0.006549791214) * y - 0.010557625006)
+ 0.011630447319) * y - 0.009279453341)
+ 0.005353579108) * y - 0.002141268741)
+ 0.000535310849) * y + 0.999936657524;
}
}
*
*
*
*
w
w
w
y * 2.0;
*
*
*
*
*
*
y
y
y
y
y
y
if (z > 0.0)
return (p + 1.0) / 2;
else
return (1.0 - p) / 2;
} // Gauss()
} // Program class
} // ns
6/8/15 2:21 PM
TesT Run
JAMES MCCAFFREY
R-squared is a value
between 0 and 1 that describes
how well the prediction model
fits the raw data.
After generating the synthetic data, the demo program uses the
data to create whats called a design matrix. A design matrix is just
the data matrix with a leading column of all 1.0 values added. There
are several different algorithms that can be used for linear regression; some can use the raw data matrix while others use a design
matrix. The demo uses a technique that requires a design matrix.
After creating the design matrix, the demo program finds the
values for four coefficients, (12.0157, 1.0180, 0.5489, -2.9566). The
coefficients are sometimes called b-values or beta-values. The first
value, 12.0157, is usually called the intercept. Its a constant not
Code download available at msdn.microsoft.com/magazine/msdnmag0715.
associated with any predictor variable. The second, third and fourth
coefficient values (1.0180, 0.5489, -2.9566) are associated with education level, work experience and sex, respectively.
The very last part of the output in Figure 1 uses the values of
the coefficients to predict the income for a hypothetical person
who has an education level of 14; 12 years of work experience; and
whose sex is 0 (male). The predicted income is 32.86, which is
calculated like so:
income = 12.0157 + (1.0180)(14) + (0.5489)(12) + (-2.9566)(0)
= 12.0157 + 14.2520 + 6.5868 + 0
= 32.86
In other words, to make a prediction using linear regression, the
predictor values are multiplied by their corresponding coefficient
values and summed. Its very simple. Notice that the leading intercept value (12.0157 in the example) can be considered a coefficient
associated with a predictor variable that always has a value of 1. This
fact, in part, explains the column of 1.0 values in the design matrix.
The essence of a linear regression problem is calculating the
values of the coefficients using the raw data or, equivalently, the
design matrix. This is not so easy. The demo uses a technique called
closed form matrix inversion, also known as the ordinary least
squares method. Alternative techniques for finding the values of
the coefficients include iteratively reweighted least squares, maximum likelihood estimation, ridge regression, gradient descent
and several others.
In Figure 1, before the prediction is made, the demo program
computes a metric called the R-squared value, which is also called
the coefficient of determination. R-squared is a value between 0
and 1 that describes how well the prediction model fits the raw
data. This is sometimes expressed as, the percentage of variation
explained by the model. Loosely interpreted, the closer R-squared
is to 1, the better the prediction model is. The demo value of 0.7207,
or 72 percent, would be considered relatively high (good) for
real-world data.
This article assumes you have at least intermediate C# programming skills, but doesnt assume you know anything about linear
regression. The demo program is too long to present in its entirety,
but the complete source code is available in the download that
accompanies this article.
76 msdn magazine
0715msdn_McCaffreyTRun_v3_76-79.indd 76
6/8/15 2:34 PM
Income ($)
msdnmagazine.com
0715msdn_McCaffreyTRun_v3_76-79.indd 77
July 2015 77
6/8/15 2:34 PM
= (X
* X) * X * Y
78 msdn magazine
0715msdn_McCaffreyTRun_v3_76-79.indd 78
Test Run
6/8/15 2:34 PM
invXt and the 10x1 Y matrix, mResult (matrix result) in the code,
has size 4x1. These values are the coefficients you need. For convenience, the values in the single column Y matrix are transferred to
an ordinary array using helper method MatrixToVector.
Calculating R-Squared
msdnmagazine.com
0715msdn_McCaffreyTRun_v3_76-79.indd 79
Wrapping Up
6/8/15 2:34 PM
DAVID S. PLATT
School and at companies all over the world. Hes the author of 11 programming
books, including Why Software Sucks (Addison-Wesley Professional, 2006)
and Introducing Microsoft .NET (Microsoft Press, 2002). Microsoft named
him a Software Legend in 2002. He wonders whether he should tape down two
of his daughters fingers so she learns how to count in octal. You can contact him
at rollthunder.com.
80 msdn magazine
0715msdn_PlattDGMS_v5_80.indd 80
6/8/15 2:30 PM
Untitled-1 1
11/26/12 3:02 PM
Untitled-4 1
3/30/15 4:32 PM