tag:blogger.com,1999:blog-68769947331183244492024-03-16T11:52:27.625-07:00The Missing BitSearching for the small things that make good software great.Jeffrey Harmonhttp://www.blogger.com/profile/07512475602963566955noreply@blogger.comBlogger13125tag:blogger.com,1999:blog-6876994733118324449.post-68812899308147284212018-06-17T18:40:00.001-07:002018-06-18T13:57:15.276-07:00HTTP Timeouts in Node<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh76Vr5HIXovvbHIM_f-RlHjyXyBpiZJDYr5ynMnBZtmkOFkuATxMTbRVS1p8aIdpHj_UOxItAXY7ZmToclG8F__h1_9PLGpeFRPtCckEPj-1v0BDBwyFrLlun-4yHjtCN7ta7UoAe5NVk/s1600/HTTP_logo.svg.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="518" data-original-width="1000" height="165" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh76Vr5HIXovvbHIM_f-RlHjyXyBpiZJDYr5ynMnBZtmkOFkuATxMTbRVS1p8aIdpHj_UOxItAXY7ZmToclG8F__h1_9PLGpeFRPtCckEPj-1v0BDBwyFrLlun-4yHjtCN7ta7UoAe5NVk/s320/HTTP_logo.svg.png" width="320" /></a></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
I needed to update some code at work the other day to add a
timeout to an HTTP GET request.<span style="mso-spacerun: yes;"> </span>Simple
enough, I thought.<span style="mso-spacerun: yes;"> </span>How hard could it be?<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
Looking back, it is pretty straight forward, and the code makes
perfect sense, but definitely wasn’t intuitive when first trying to get it
working.<span style="mso-spacerun: yes;"> </span>I’m writing this mainly as a
note to myself about the proper way to handle this in the future.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<h2>
The Starting Point<o:p></o:p></h2>
<div class="MsoNormal">
The code I was updating called a GET endpoint on localhost.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal" style="background: #1E1E1E; line-height: 14.25pt; margin-bottom: .0001pt; margin-bottom: 0in;">
<span style="color: #569cd6; font-family: "consolas"; font-size: 10.5pt;">var</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"> </span><span style="color: #9cdcfe; font-family: "consolas"; font-size: 10.5pt;">req</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"> = </span><span style="color: #9cdcfe; font-family: "consolas"; font-size: 10.5pt;">http</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;">.</span><span style="color: #dcdcaa; font-family: "consolas"; font-size: 10.5pt;">get</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;">(</span><span style="color: #9cdcfe; font-family: "consolas"; font-size: 10.5pt;">url</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;">, </span><span style="color: #9cdcfe; font-family: "consolas"; font-size: 10.5pt;">res</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"> </span><span style="color: #569cd6; font-family: "consolas"; font-size: 10.5pt;">=></span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"> {<o:p></o:p></span></div>
<div class="MsoNormal" style="background: #1E1E1E; line-height: 14.25pt; margin-bottom: .0001pt; margin-bottom: 0in;">
<span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"> </span><span style="color: #608b4e; font-family: "consolas"; font-size: 10.5pt;">//handle success</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"><o:p></o:p></span></div>
<div class="MsoNormal" style="background: #1E1E1E; line-height: 14.25pt; margin-bottom: .0001pt; margin-bottom: 0in;">
<span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;">}).</span><span style="color: #dcdcaa; font-family: "consolas"; font-size: 10.5pt;">on</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;">(</span><span style="color: #ce9178; font-family: "consolas"; font-size: 10.5pt;">'error'</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;">, </span><span style="color: #9cdcfe; font-family: "consolas"; font-size: 10.5pt;">e</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"> </span><span style="color: #569cd6; font-family: "consolas"; font-size: 10.5pt;">=></span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"> {<o:p></o:p></span></div>
<div class="MsoNormal" style="background: #1E1E1E; line-height: 14.25pt; margin-bottom: .0001pt; margin-bottom: 0in;">
<span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"> </span><span style="color: #608b4e; font-family: "consolas"; font-size: 10.5pt;">//handle error</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"><o:p></o:p></span></div>
<div class="MsoNormal" style="background: #1E1E1E; line-height: 14.25pt; margin-bottom: .0001pt; margin-bottom: 0in;">
<span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;">});<o:p></o:p></span></div>
<br />
<h2>
Adding a Timeout<o:p></o:p></h2>
<div class="MsoNormal">
I hadn't added a timeout to a request in Node before, using
the built-in HTTP library, so I did what any red-blooded developer would do,
and copy-pasted from elsewhere in the code that was doing something similar.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal" style="background: #1E1E1E; line-height: 14.25pt; margin-bottom: .0001pt; margin-bottom: 0in;">
<span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"> </span><span style="color: #569cd6; font-family: "consolas"; font-size: 10.5pt;">var</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"> </span><span style="color: #9cdcfe; font-family: "consolas"; font-size: 10.5pt;">req</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"> = </span><span style="color: #9cdcfe; font-family: "consolas"; font-size: 10.5pt;">http</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;">.</span><span style="color: #dcdcaa; font-family: "consolas"; font-size: 10.5pt;">get</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;">(</span><span style="color: #9cdcfe; font-family: "consolas"; font-size: 10.5pt;">url</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;">, </span><span style="color: #9cdcfe; font-family: "consolas"; font-size: 10.5pt;">res</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"> </span><span style="color: #569cd6; font-family: "consolas"; font-size: 10.5pt;">=></span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"> {<o:p></o:p></span></div>
<div class="MsoNormal" style="background: #1E1E1E; line-height: 14.25pt; margin-bottom: .0001pt; margin-bottom: 0in;">
<span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"> </span><span style="color: #608b4e; font-family: "consolas"; font-size: 10.5pt;">//handle success</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"><o:p></o:p></span></div>
<div class="MsoNormal" style="background: #1E1E1E; line-height: 14.25pt; margin-bottom: .0001pt; margin-bottom: 0in;">
<span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"> }).</span><span style="color: #dcdcaa; font-family: "consolas"; font-size: 10.5pt;">on</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;">(</span><span style="color: #ce9178; font-family: "consolas"; font-size: 10.5pt;">'error'</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;">, </span><span style="color: #9cdcfe; font-family: "consolas"; font-size: 10.5pt;">e</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"> </span><span style="color: #569cd6; font-family: "consolas"; font-size: 10.5pt;">=></span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"> {<o:p></o:p></span></div>
<div class="MsoNormal" style="background: #1E1E1E; line-height: 14.25pt; margin-bottom: .0001pt; margin-bottom: 0in;">
<span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"> </span><span style="color: #608b4e; font-family: "consolas"; font-size: 10.5pt;">//handle error</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"><o:p></o:p></span></div>
<div class="MsoNormal" style="background: #1E1E1E; line-height: 14.25pt; margin-bottom: .0001pt; margin-bottom: 0in;">
<span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"> }).</span><span style="color: #dcdcaa; font-family: "consolas"; font-size: 10.5pt;">on</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;">(</span><span style="color: #ce9178; font-family: "consolas"; font-size: 10.5pt;">'socket'</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;">, </span><span style="color: #9cdcfe; font-family: "consolas"; font-size: 10.5pt;">sock</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"> </span><span style="color: #569cd6; font-family: "consolas"; font-size: 10.5pt;">=></span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"> {<o:p></o:p></span></div>
<div class="MsoNormal" style="background: #1E1E1E; line-height: 14.25pt; margin-bottom: .0001pt; margin-bottom: 0in;">
<span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"> </span><span style="color: #9cdcfe; font-family: "consolas"; font-size: 10.5pt;">sock</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;">.</span><span style="color: #dcdcaa; font-family: "consolas"; font-size: 10.5pt;">setTimeout</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;">(</span><span style="color: #b5cea8; font-family: "consolas"; font-size: 10.5pt;">500</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;">);<o:p></o:p></span></div>
<div class="MsoNormal" style="background: #1E1E1E; line-height: 14.25pt; margin-bottom: .0001pt; margin-bottom: 0in;">
<span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"> </span><span style="color: #9cdcfe; font-family: "consolas"; font-size: 10.5pt;">sock</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;">.</span><span style="color: #dcdcaa; font-family: "consolas"; font-size: 10.5pt;">on</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;">(</span><span style="color: #ce9178; font-family: "consolas"; font-size: 10.5pt;">'timeout'</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;">, () </span><span style="color: #569cd6; font-family: "consolas"; font-size: 10.5pt;">=></span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"> {<o:p></o:p></span></div>
<div class="MsoNormal" style="background: #1E1E1E; line-height: 14.25pt; margin-bottom: .0001pt; margin-bottom: 0in;">
<span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"> </span><span style="color: #9cdcfe; font-family: "consolas"; font-size: 10.5pt;">req</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;">.</span><span style="color: #dcdcaa; font-family: "consolas"; font-size: 10.5pt;">abort</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;">();<o:p></o:p></span></div>
<div class="MsoNormal" style="background: #1E1E1E; line-height: 14.25pt; margin-bottom: .0001pt; margin-bottom: 0in;">
<span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"> });<o:p></o:p></span></div>
<div class="MsoNormal" style="background: #1E1E1E; line-height: 14.25pt; margin-bottom: .0001pt; margin-bottom: 0in;">
<span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"> });<o:p></o:p></span></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
This seemed oddly confusing for something so simple, but
worked fine.<span style="mso-spacerun: yes;"> </span>Reading <a href="https://nodejs.org/api/http.html">the docs</a>, I could
see that the 'socket' event fires when a socket is assigned to the request.<span style="mso-spacerun: yes;"> </span>We then set a timeout directly on the socket,
and abort the request once that occurs.</div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
I thought the abort wasn't necessary, since the request had already
timed out, so I removed it and it still worked.<span style="mso-spacerun: yes;">
</span>The timeout event would fire right away,
instead of waiting the default 2 minutes, like it used to, to error out.<span style="mso-spacerun: yes;"> </span>I was actually missing something important,
but hadn't noticed it yet.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<h2>
HTTPS<o:p></o:p></h2>
<div class="MsoNormal">
Next, I had to update http to https, which normally just
means adding a single letter to your require statement.<span style="mso-spacerun: yes;"> </span>Since this was localhost though, and didn't
have a certificate, I also needed to ignore certificate errors.<span style="mso-spacerun: yes;"> </span>Again, I used my normal trick of finding
another call that did this, and copying from it.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
I found a POST call to a different localhost endpoint, and
saw that it was using https.request (instead of https.get) and that it was
using an options object, instead of passing the URL as a string.<span style="mso-spacerun: yes;"> </span>The options object had a 'rejectUnauthorized' property, which is what I needed to ignore certificate errors.<span style="mso-spacerun: yes;"> </span>Why they used the term 'Unauthorized',
instead of 'InvalidCert' or something similar, is beyond me.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
I figured that request() just always used an option object,
instead of a URL like get() did, and to get access to the 'rejectUnauthorized' property, I would need to need to switch to it.<span style="mso-spacerun: yes;">
</span>So, I changed my http.get to https.request, passed it an option object,
breaking out the host, path, port and method, and passed that in, instead of
the URL string.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal" style="background: #1E1E1E; line-height: 14.25pt; margin-bottom: .0001pt; margin-bottom: 0in;">
<span style="color: #569cd6; font-family: "consolas"; font-size: 10.5pt;">let</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"> </span><span style="color: #9cdcfe; font-family: "consolas"; font-size: 10.5pt;">options</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"> = {<o:p></o:p></span></div>
<div class="MsoNormal" style="background: #1E1E1E; line-height: 14.25pt; margin-bottom: .0001pt; margin-bottom: 0in;">
<span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"><span style="mso-spacerun: yes;"> </span></span><span style="color: #9cdcfe; font-family: "consolas"; font-size: 10.5pt;">host:</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"> </span><span style="color: #ce9178; font-family: "consolas"; font-size: 10.5pt;">'localhost'</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;">,<o:p></o:p></span></div>
<div class="MsoNormal" style="background: #1E1E1E; line-height: 14.25pt; margin-bottom: .0001pt; margin-bottom: 0in;">
<span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"><span style="mso-spacerun: yes;"> </span></span><span style="color: #9cdcfe; font-family: "consolas"; font-size: 10.5pt;">path:</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"> </span><span style="color: #ce9178; font-family: "consolas"; font-size: 10.5pt;">'/resource'</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;">,<o:p></o:p></span></div>
<div class="MsoNormal" style="background: #1E1E1E; line-height: 14.25pt; margin-bottom: .0001pt; margin-bottom: 0in;">
<span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"><span style="mso-spacerun: yes;"> </span></span><span style="color: #9cdcfe; font-family: "consolas"; font-size: 10.5pt;">port:</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"> </span><span style="color: #ce9178; font-family: "consolas"; font-size: 10.5pt;">'12345'</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;">,<o:p></o:p></span></div>
<div class="MsoNormal" style="background: #1E1E1E; line-height: 14.25pt; margin-bottom: .0001pt; margin-bottom: 0in;">
<span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"><span style="mso-spacerun: yes;"> </span></span><span style="color: #9cdcfe; font-family: "consolas"; font-size: 10.5pt;">method:</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"> </span><span style="color: #ce9178; font-family: "consolas"; font-size: 10.5pt;">'GET'</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;">,<o:p></o:p></span></div>
<div class="MsoNormal" style="background: #1E1E1E; line-height: 14.25pt; margin-bottom: .0001pt; margin-bottom: 0in;">
<span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"><span style="mso-spacerun: yes;"> </span></span><span style="color: #9cdcfe; font-family: "consolas"; font-size: 10.5pt;">rejectUnauthorized:</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"> </span><span style="color: #569cd6; font-family: "consolas"; font-size: 10.5pt;">false</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"><o:p></o:p></span></div>
<div class="MsoNormal" style="background: #1E1E1E; line-height: 14.25pt; margin-bottom: .0001pt; margin-bottom: 0in;">
<span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;">};<o:p></o:p></span></div>
<div class="MsoNormal" style="background: #1E1E1E; line-height: 14.25pt; margin-bottom: .0001pt; margin-bottom: 0in;">
<span style="color: #569cd6; font-family: "consolas"; font-size: 10.5pt;">var</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"> </span><span style="color: #9cdcfe; font-family: "consolas"; font-size: 10.5pt;">req</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"> = </span><span style="color: #9cdcfe; font-family: "consolas"; font-size: 10.5pt;">http</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;">.</span><span style="color: #dcdcaa; font-family: "consolas"; font-size: 10.5pt;">request</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;">(</span><span style="color: #9cdcfe; font-family: "consolas"; font-size: 10.5pt;">options</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;">, </span><span style="color: #9cdcfe; font-family: "consolas"; font-size: 10.5pt;">res</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"> </span><span style="color: #569cd6; font-family: "consolas"; font-size: 10.5pt;">=></span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"> {<o:p></o:p></span></div>
<div class="MsoNormal" style="background: #1E1E1E; line-height: 14.25pt; margin-bottom: .0001pt; margin-bottom: 0in;">
<span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"> </span><span style="color: #608b4e; font-family: "consolas"; font-size: 10.5pt;">//handle success</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"><o:p></o:p></span></div>
<div class="MsoNormal" style="background: #1E1E1E; line-height: 14.25pt; margin-bottom: .0001pt; margin-bottom: 0in;">
<span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;">}).</span><span style="color: #dcdcaa; font-family: "consolas"; font-size: 10.5pt;">on</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;">(</span><span style="color: #ce9178; font-family: "consolas"; font-size: 10.5pt;">'error'</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;">, </span><span style="color: #9cdcfe; font-family: "consolas"; font-size: 10.5pt;">e</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"> </span><span style="color: #569cd6; font-family: "consolas"; font-size: 10.5pt;">=></span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"> {<o:p></o:p></span></div>
<div class="MsoNormal" style="background: #1E1E1E; line-height: 14.25pt; margin-bottom: .0001pt; margin-bottom: 0in;">
<span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"> </span><span style="color: #608b4e; font-family: "consolas"; font-size: 10.5pt;">//handle error</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"><o:p></o:p></span></div>
<div class="MsoNormal" style="background: #1E1E1E; line-height: 14.25pt; margin-bottom: .0001pt; margin-bottom: 0in;">
<span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;">}).</span><span style="color: #dcdcaa; font-family: "consolas"; font-size: 10.5pt;">on</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;">(</span><span style="color: #ce9178; font-family: "consolas"; font-size: 10.5pt;">'socket'</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;">, </span><span style="color: #9cdcfe; font-family: "consolas"; font-size: 10.5pt;">sock</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"> </span><span style="color: #569cd6; font-family: "consolas"; font-size: 10.5pt;">=></span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"> {<o:p></o:p></span></div>
<div class="MsoNormal" style="background: #1E1E1E; line-height: 14.25pt; margin-bottom: .0001pt; margin-bottom: 0in;">
<span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"> </span><span style="color: #9cdcfe; font-family: "consolas"; font-size: 10.5pt;">sock</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;">.</span><span style="color: #dcdcaa; font-family: "consolas"; font-size: 10.5pt;">setTimeout</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;">(</span><span style="color: #b5cea8; font-family: "consolas"; font-size: 10.5pt;">500</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;">);<o:p></o:p></span></div>
<div class="MsoNormal" style="background: #1E1E1E; line-height: 14.25pt; margin-bottom: .0001pt; margin-bottom: 0in;">
<span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"> </span><span style="color: #9cdcfe; font-family: "consolas"; font-size: 10.5pt;">sock</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;">.</span><span style="color: #dcdcaa; font-family: "consolas"; font-size: 10.5pt;">on</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;">(</span><span style="color: #ce9178; font-family: "consolas"; font-size: 10.5pt;">'timeout'</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;">, () </span><span style="color: #569cd6; font-family: "consolas"; font-size: 10.5pt;">=></span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"> { });<o:p></o:p></span></div>
<div class="MsoNormal" style="background: #1E1E1E; line-height: 14.25pt; margin-bottom: .0001pt; margin-bottom: 0in;">
<span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;">});<o:p></o:p></span></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
Simple enough, but it didn't work.<span style="mso-spacerun: yes;"> </span>The call would hang.<span style="mso-spacerun: yes;"> </span>It took some digging, but it turns out I
missed an important line from the request() example I copied from.<span style="mso-spacerun: yes;"> </span>I knew that the get() method I was using
before would automatically set the method to GET, but apparently it also calls end()
on the request, which I didn't realize was needed.<span style="mso-spacerun: yes;"> </span>It makes sense, as the way request are
modified by method chaining means you wouldn't know when you were done updating
the request, but it wasn't obvious at first.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
After I got that figured that out, I then realized that both
get() and request() can take either a url or options object, so I actually didn't
need to use request(), and switched back to get() (and removed the call to end()
I had just added).<span style="mso-spacerun: yes;"> </span>Everything was
working now, until I pushed the code to an environment where the logging code
actually wrote to somewhere.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<h2>
Aborting<o:p></o:p></h2>
<div class="MsoNormal">
It turns out that whenever my request timed out, I was still
logging an error, but only after 2 minutes.<span style="mso-spacerun: yes;">
</span>Again, I dug through the docs and found that when a request times out,
it doesn't actually end.<span style="mso-spacerun: yes;"> </span>It would keep
going until it was forcefully timed-out and killed, after the default 2-minute
timeout.<span style="mso-spacerun: yes;"> </span>In the timeout event, you still
need to manually abort the request, which the original code I copied from
did.<span style="mso-spacerun: yes;"> </span>Yet another example of it never
being a good idea to remove code you don't understand, until you understand it.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
That change still didn't get everything working though. <span style="mso-spacerun: yes;"> </span>The code would still throw an error ("socket hang up"), but it
would do it immediately after the timeout, instead of after 2 minutes.<span style="mso-spacerun: yes;"> </span>The final piece was realizing that aborting a
request still throws an error, but sets the 'code' property of the error object
to 'ECONNRESET'.<span style="mso-spacerun: yes;"> </span>So when I checked for
that in the error handler, I could successfully ignore timeouts, and handle
regular errors. <span style="mso-spacerun: yes;"> </span>Annoyingly though,
error.code is also set to 'ECONNRESET' if the server resets the connection, so to
be truly accurate, you would need to set a variable in the 'timeout' event that
the 'error' event could check.<span style="mso-spacerun: yes;"> </span>For my
needs though, that wasn't necessary, and I just checked error.code.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<h2>
Wrapping Up<o:p></o:p></h2>
<div class="MsoNormal">
In the end, I got the code working, and everything makes
sense now.<span style="mso-spacerun: yes;"> </span>While I understand the logic
behind most design decisions of the API (the name of 'rejectUnauthorized' not
withstanding), I feel like many parts aren't very intuitive, especially for
those coming from a different background, such as .NET.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
After finding out about request.setTimeout, which mimicks
the more verbose socket code, the final code is below:<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal" style="background: #1E1E1E; line-height: 14.25pt; margin-bottom: .0001pt; margin-bottom: 0in;">
<span style="color: #569cd6; font-family: "consolas"; font-size: 10.5pt;">let</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"> </span><span style="color: #9cdcfe; font-family: "consolas"; font-size: 10.5pt;">options</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"> = {<o:p></o:p></span></div>
<div class="MsoNormal" style="background: #1E1E1E; line-height: 14.25pt; margin-bottom: .0001pt; margin-bottom: 0in;">
<span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"><span style="mso-spacerun: yes;"> </span></span><span style="color: #9cdcfe; font-family: "consolas"; font-size: 10.5pt;">host:</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"> </span><span style="color: #ce9178; font-family: "consolas"; font-size: 10.5pt;">'localhost'</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;">,<o:p></o:p></span></div>
<div class="MsoNormal" style="background: #1E1E1E; line-height: 14.25pt; margin-bottom: .0001pt; margin-bottom: 0in;">
<span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"><span style="mso-spacerun: yes;"> </span></span><span style="color: #9cdcfe; font-family: "consolas"; font-size: 10.5pt;">path:</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"> </span><span style="color: #ce9178; font-family: "consolas"; font-size: 10.5pt;">'/resource'</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;">,<o:p></o:p></span></div>
<div class="MsoNormal" style="background: #1E1E1E; line-height: 14.25pt; margin-bottom: .0001pt; margin-bottom: 0in;">
<span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"><span style="mso-spacerun: yes;"> </span></span><span style="color: #9cdcfe; font-family: "consolas"; font-size: 10.5pt;">port:</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"> </span><span style="color: #ce9178; font-family: "consolas"; font-size: 10.5pt;">'12345'</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;">,<o:p></o:p></span></div>
<div class="MsoNormal" style="background: #1E1E1E; line-height: 14.25pt; margin-bottom: .0001pt; margin-bottom: 0in;">
<span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"><span style="mso-spacerun: yes;"> </span></span><span style="color: #9cdcfe; font-family: "consolas"; font-size: 10.5pt;">method:</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"> </span><span style="color: #ce9178; font-family: "consolas"; font-size: 10.5pt;">'GET'</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;">,<o:p></o:p></span></div>
<div class="MsoNormal" style="background: #1E1E1E; line-height: 14.25pt; margin-bottom: .0001pt; margin-bottom: 0in;">
<span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"><span style="mso-spacerun: yes;"> </span></span><span style="color: #9cdcfe; font-family: "consolas"; font-size: 10.5pt;">rejectUnauthorized:</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"> </span><span style="color: #569cd6; font-family: "consolas"; font-size: 10.5pt;">false</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"><o:p></o:p></span></div>
<div class="MsoNormal" style="background: #1E1E1E; line-height: 14.25pt; margin-bottom: .0001pt; margin-bottom: 0in;">
<span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;">};<o:p></o:p></span></div>
<div class="MsoNormal" style="background: #1E1E1E; line-height: 14.25pt; margin-bottom: .0001pt; margin-bottom: 0in;">
<span style="color: #569cd6; font-family: "consolas"; font-size: 10.5pt;">var</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"> </span><span style="color: #9cdcfe; font-family: "consolas"; font-size: 10.5pt;">req</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"> = </span><span style="color: #9cdcfe; font-family: "consolas"; font-size: 10.5pt;">https</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;">.</span><span style="color: #dcdcaa; font-family: "consolas"; font-size: 10.5pt;">get</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;">(</span><span style="color: #9cdcfe; font-family: "consolas"; font-size: 10.5pt;">options</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;">, </span><span style="color: #9cdcfe; font-family: "consolas"; font-size: 10.5pt;">res</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"> </span><span style="color: #569cd6; font-family: "consolas"; font-size: 10.5pt;">=></span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"> {<o:p></o:p></span></div>
<div class="MsoNormal" style="background: #1E1E1E; line-height: 14.25pt; margin-bottom: .0001pt; margin-bottom: 0in;">
<span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"> </span><span style="color: #608b4e; font-family: "consolas"; font-size: 10.5pt;">//handle success</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"><o:p></o:p></span></div>
<div class="MsoNormal" style="background: #1E1E1E; line-height: 14.25pt; margin-bottom: .0001pt; margin-bottom: 0in;">
<span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;">}).</span><span style="color: #dcdcaa; font-family: "consolas"; font-size: 10.5pt;">on</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;">(</span><span style="color: #ce9178; font-family: "consolas"; font-size: 10.5pt;">'error'</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;">, </span><span style="color: #569cd6; font-family: "consolas"; font-size: 10.5pt;">function</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;">(</span><span style="color: #9cdcfe; font-family: "consolas"; font-size: 10.5pt;">err</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;">) {<o:p></o:p></span></div>
<div class="MsoNormal" style="background: #1E1E1E; line-height: 14.25pt; margin-bottom: .0001pt; margin-bottom: 0in;">
<span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"><span style="mso-spacerun: yes;"> </span></span><span style="color: #608b4e; font-family: "consolas"; font-size: 10.5pt;">//ignore timeouts</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"><o:p></o:p></span></div>
<div class="MsoNormal" style="background: #1E1E1E; line-height: 14.25pt; margin-bottom: .0001pt; margin-bottom: 0in;">
<span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"><span style="mso-spacerun: yes;"> </span></span><span style="color: #c586c0; font-family: "consolas"; font-size: 10.5pt;">if</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"> (</span><span style="color: #9cdcfe; font-family: "consolas"; font-size: 10.5pt;">err</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;">.</span><span style="color: #9cdcfe; font-family: "consolas"; font-size: 10.5pt;">code</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"> === </span><span style="color: #ce9178; font-family: "consolas"; font-size: 10.5pt;">"ECONNRESET"</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;">) {<o:p></o:p></span></div>
<div class="MsoNormal" style="background: #1E1E1E; line-height: 14.25pt; margin-bottom: .0001pt; margin-bottom: 0in;">
<span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"><span style="mso-spacerun: yes;"> </span></span><span style="color: #c586c0; font-family: "consolas"; font-size: 10.5pt;">return</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;">;<o:p></o:p></span></div>
<div class="MsoNormal" style="background: #1E1E1E; line-height: 14.25pt; margin-bottom: .0001pt; margin-bottom: 0in;">
<span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"><span style="mso-spacerun: yes;"> </span>}<o:p></o:p></span></div>
<div class="MsoNormal" style="background: #1E1E1E; line-height: 14.25pt; margin-bottom: .0001pt; margin-bottom: 0in;">
<span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"><span style="mso-spacerun: yes;"> </span></span><span style="color: #608b4e; font-family: "consolas"; font-size: 10.5pt;">//handle error</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"><o:p></o:p></span></div>
<div class="MsoNormal" style="background: #1E1E1E; line-height: 14.25pt; margin-bottom: .0001pt; margin-bottom: 0in;">
<span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;">}<o:p></o:p></span></div>
<div class="MsoNormal" style="background: #1E1E1E; line-height: 14.25pt; margin-bottom: .0001pt; margin-bottom: 0in;">
<span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;">).</span><span style="color: #dcdcaa; font-family: "consolas"; font-size: 10.5pt;">setTimeout</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;">(</span><span style="color: #b5cea8; font-family: "consolas"; font-size: 10.5pt;">25</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;">, () </span><span style="color: #569cd6; font-family: "consolas"; font-size: 10.5pt;">=></span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"> {<o:p></o:p></span></div>
<div class="MsoNormal" style="background: #1E1E1E; line-height: 14.25pt; margin-bottom: .0001pt; margin-bottom: 0in;">
<span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;"><span style="mso-spacerun: yes;"> </span></span><span style="color: #9cdcfe; font-family: "consolas"; font-size: 10.5pt;">req</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;">.</span><span style="color: #dcdcaa; font-family: "consolas"; font-size: 10.5pt;">abort</span><span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;">();<o:p></o:p></span></div>
<div class="MsoNormal" style="background: #1E1E1E; line-height: 14.25pt; margin-bottom: .0001pt; margin-bottom: 0in;">
<span style="color: #d4d4d4; font-family: "consolas"; font-size: 10.5pt;">});<o:p></o:p></span></div>
<br />Jeffrey Harmonhttp://www.blogger.com/profile/07512475602963566955noreply@blogger.com3tag:blogger.com,1999:blog-6876994733118324449.post-1437034531461126732017-12-21T17:53:00.002-08:002017-12-21T18:06:05.621-08:00How to Use Span<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhgP1b6k0NMXIqn57khX_f3MfILJlYAXJPS3ivTS-Y9uTqGfbdXNy5s_BKYjb4wfv0wF5SpzNItKQuOhde8xgs83T_v5urdKuMnqLZ6q2VTOxPRFB9DoAJ42UcTe2YPhkiqb94x0Ts5jJ4/s1600/SpanOfTHeader.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="360" data-original-width="640" height="180" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhgP1b6k0NMXIqn57khX_f3MfILJlYAXJPS3ivTS-Y9uTqGfbdXNy5s_BKYjb4wfv0wF5SpzNItKQuOhde8xgs83T_v5urdKuMnqLZ6q2VTOxPRFB9DoAJ42UcTe2YPhkiqb94x0Ts5jJ4/s320/SpanOfTHeader.jpg" width="320" /></a></div>
<br />
I've read plenty of articles about Span<t> over the past year or two, and have been following its development from a distance, without actually trying any of the early iterations of it. When Microsoft released a blog post <a href="https://blogs.msdn.microsoft.com/dotnet/2017/11/15/welcome-to-c-7-2-and-span/">welcoming Span<t></t></a>, I figured it was finally time to try it out myself.</t><br />
<t><br /></t>
<br />
<h3>
Where Is It?</h3>
<div>
Amazingly, the mentioned post above, and even the Channel 9 video <a href="https://channel9.msdn.com/Events/Connect/2017/T125">C# 7.2: Understanding Span</a>, never actually mention how to get Span<t> compiling. Searching for people that have actually used it, turned up nothing.</t></div>
<div>
<br />
It wasn't until I read a comment on the article that I saw that you still need to reference the Nuget library System.Memory to get it to work. Even more, the library is still in pre-release, so it is not actually officially released yet. Based on the wording of the announcement post, this was surprising.<br />
<br />
It appears that .NET Core 2.1 (and I assume .NET Standard 2.1) will have full support, as well as the additional library changes they keep mentioning, that have all of the overloads supporting span.<br />
<br /></div>
<h3>
Adding Support</h3>
<div>
Anyways, the only thing you need to do, once you update to Visual Studio 2017 15.5, is to add the nuget package.</div>
<div>
<br /></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">Install-Package System.Memory -Prerelease</span></div>
<div>
<br /></div>
<div>
You may still get some red squigglies with some code, as the editor doesn't have full support for it yet, but the following should compile.</div>
<div>
<br /></div>
<div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">var array = new int[10];</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">Span<int> span = array;</int></span></div>
</div>
<div>
<br /></div>
Jeffrey Harmonhttp://www.blogger.com/profile/07512475602963566955noreply@blogger.com1tag:blogger.com,1999:blog-6876994733118324449.post-77594757821080586102014-03-27T07:00:00.000-07:002014-03-27T07:00:07.832-07:00Loading Real Images to the Windows Phone Emulator<p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg86uSGmWand4PHlu1T4vgPmq8NidANp06Q9x9TflvqkPcLfSpi1sxW5tsJqwaWi7Jsb4YRv5p3_ERlF-4DL18ZjQVu5HjScRMZX-KMAt3wMOad2thx_cldPYdbIte1vo6J_M4xSWq11k0/s1600-h/default_image_0%25255B2%25255D.png"><img title="default_image_0" style="border-top: 0px; border-right: 0px; border-bottom: 0px; float: none; margin-left: auto; border-left: 0px; display: block; margin-right: auto" border="0" alt="default_image_0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhECw-g796ezqgrw23v9GylzoT5b-cDEsmAV-zjb75WApqDiN6pkBJIJwofKKMW67iem-767D4resyFLqx176GRwyLMKgeRdH1aMfW67Ym99TzwWL6nf1u82cqdd8Oe7YSJe-INQWDJRu4/?imgmax=800" width="244" height="184"></a></p>
<p>If you have ever used a Windows Phone, you have seen the 9 images loaded on every phone by default. And if you are a developer, you have also seen them on the emulator, and noticed that they are the ONLY real images available without doing some tricks to get extra ones on there.</p>
<p>This is fine for testing, but I’ve seen too many screen shots in the store, and even promotional images and videos using them, even when the images are completely inappropriate for the app. There is a great post by Matt Lacey about <a href="http://blog.mrlacey.co.uk/2014/03/9-images-that-shouldnt-appear-as-part.html" target="_blank">the 9 images that shouldn’t appear as part of your screen shots</a> where he talks about this issue.</p>
<p>The following images were found in a few minutes by doing a quick search of the Photo section of the Windows Phone store.</p>
<p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhuP76ppRz6ycvMcOCFbPd88B0oO7v7zMTimFDQsuTxSs90GnpK24GLRm6hxUNn23Axibrf9EgsdS8pOy4RXB13Zup8v91VtUYnEGbwnJMOZqmBw0ZqsKj8Tpw0QNAJPvSBaGHlDW8NU4s/s1600-h/wp_ss_20140326_0001%25255B5%25255D.png"><img title="wp_ss_20140326_0001" style="border-top: 0px; border-right: 0px; border-bottom: 0px; border-left: 0px; display: inline" border="0" alt="wp_ss_20140326_0001" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhARxHyWrMYUPIblh3tgblB-zR9cfa8ykWGsLkS7iYMEvRnHt7b7DQT5EMkOvP5QyPa83e3CwGfBnSBP0USPrHCtQYzyUIdPmRYyao3W28V9axHtpg3vuBwEVCzhWauGIC0fhyphenhyphenqSth9gdE/?imgmax=800" width="204" height="337"></a> <a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjtf-arA9Hm3Qru4xzdRLD5iDGAniZ6_CtOK0T_P0yPI0LPxPG8rARxYBHpi86dS8PSVD4sunhM10MoDYLqqG2fOOg-GpCEbS7evgpheeYbGZC4q4ejetFj9nuSve-Xxi36MbP_9PcV3t8/s1600-h/wp_ss_20140326_0002%25255B3%25255D.png"><img title="wp_ss_20140326_0002" style="border-top: 0px; border-right: 0px; border-bottom: 0px; border-left: 0px; display: inline" border="0" alt="wp_ss_20140326_0002" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiXbKJiXRvSk-LG0HqywnwXbJC6Tz90eOAsnxDBGp4dakWYaDeuvEI3RXWEdcq2bzdWqIxa-yopy9_hdM5KPLP0UWQyRsm7auyJMXe6PtorgLf6ufSAYvZsRinlTezzf1RSl0NM-lGCty4/?imgmax=800" width="204" height="337"></a> <a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi-OwWyRHYBjXQ57EnzZwGRzWiwzP-4W4lBQKONvhuQ8KCTKlFeSjiQx8Fj72eFpcJxD5EQo9sot8Ajg4YqAMDk35Q0W2JGD28Dypgxsuq9xcSm44nf9Edu2Bgx1pMY1atO9SYz2zOsHmI/s1600-h/wp_ss_20140326_0003%25255B3%25255D.png"><img title="wp_ss_20140326_0003" style="border-top: 0px; border-right: 0px; border-bottom: 0px; border-left: 0px; display: inline" border="0" alt="wp_ss_20140326_0003" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjsvWAxb7iOO8LQTAUQ130UyXWtfvxShyaYcnKx_bKWeXAn_WS5qII1dUBwOtWGTLWJRVCBdcC8IfiNpl47JeNtgwoWcPnoqz-P3d7WKu1qc-H1EVmA1H-6dnSnJB2ll27Hz5oBaubKt5A/?imgmax=800" width="204" height="337"></a> <a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhAxvGEb05Cxn5FIJpbyXL2WLHupl1KaQzuXKSyPsHyyzCzSwxtBHszluSPoE4bgmJtEqApK-ux9XaEhpiRc9AKxtMTMibctwS-De8QtSZ9BMBau7ZS9-zuYWtLDPi2EpqPnt-r6RSE5Gs/s1600-h/wp_ss_20140326_0004%25255B3%25255D.png"><img title="wp_ss_20140326_0004" style="border-top: 0px; border-right: 0px; border-bottom: 0px; border-left: 0px; display: inline" border="0" alt="wp_ss_20140326_0004" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEitO2yfxvmaSilxCiurnVUtBGyyA09gZsIkn3vLnwo7dyC6a-Iprnp4ldSI9sfefFw7FUQs6l1dhOK2RVN0Bkr-cfU6YOGTGgjs1mKztzdL0LPLQ9zhf5UY46DTXnpTQjMFly7S1-ol-D8/?imgmax=800" width="204" height="337"></a></p>
<h3>Loading Real Photos</h3>
<p>When I wrote my first Windows Phone app, <a href="http://www.memorylage.com" target="_blank">Memorylage</a>, just over a year ago, I wanted to make sure that my screen shots and promotional images really showed off my app, but wasn’t sure at first how to get any other images on there. I could have taken screen shots directly from my phone, but that wouldn’t work for the 16:9 resolution that the 8X used. Also, I made a promotional video doing a screen capture of the emulator, so I needed them on there for that as well.</p>
<p>I tried uploading some images to a web page on my site, and manually downloading them from the browser on the emulator, but that wasn’t very efficient, and I needed a lot of images to show off my app. I needed a better way.</p>
<p>I ended up finding a command line program that is part of the Windows Phone SDK called IsolatedStorageExplorerTool.exe. This lets you view the contents of an app’s isolated storage, either on a device, or on the emulator. You can also download the contents to your computer, or even <strong>upload new content from your computer</strong>.</p>
<p>I had found a way to get files onto the emulator, but the program wasn’t exactly user friendly, and is limited in what it can do. I ended up writing a simple phone app that took the images within its local storage, and saved them to the camera roll and saved pictures folder. (These are the only two parts of a user’s photo library that an app can write to.) I then used the .exe to load images to that app’s storage, and ran the app to get the images loaded directly into the emulator.</p>
<h3>Doing Better</h3>
<p>It all worked, and I was able to do all of my promotional material from the emulator without having to look at the default pictures. I felt like the whole process could be improved though, but didn’t have time then, and left it. Recently, however, I have been seeing the images still used in apps, even by seasoned devs, and felt it was time to take my solution, clean it up, and release it for others to use.</p>
<p>So, without further ado, here is the Visual Studio solution for my app. (I am planning on hosting it on CodePlex, but was having trouble getting Git to successfully upload to it last night, so will update the post once it is there)</p>
<p><a href="https://onedrive.live.com/redir?resid=89B78560E756FA16!45966&authkey=!AEOcxl_GBiEyeOw&ithint=file%2c.zip" target="_blank">WPEmulatorImageLoader.zip</a></p>
<h3>One Solution, Two Apps</h3>
<p>The first project within the solution is a desktop app that allows you to select a folder containing images you want loaded to the phone’s camera roll, as well as a folder for images that will go in the saved pictures folder. There is then a button to load those pictures to the emulator, which will use IsolatedStorageExplorerTool.exe internally.</p>
<p>The second project is a Windows Phone app that has two buttons for loading images from isolated storage to the camera roll and saved pictures folder on the phone/emulator. (Pardon the programmer UI)</p>
<p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhGkaw8sCy6-yyCeHqKozUeT09vBZTKZM8hptpHcrK2Z9qYD1qig9Xv94hO8jIIgZx8t987Ufw14nY4l30EnxRl55a_ZChCoCYy2Geop5UCL8eqB6oWMoP-q79VU5wHQ3IItkqJFQ6cA8c/s1600-h/ImageLoaderDesktopApp%25255B2%25255D.png"><img title="ImageLoaderDesktopApp" style="border-top: 0px; border-right: 0px; border-bottom: 0px; border-left: 0px; display: inline" border="0" alt="ImageLoaderDesktopApp" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiohjIGCiN8x8VqJhe8lvtjkWPX_jegtmxFxptOiyYdJemWwtwy2Ne8a9CcokZR1cZSAiiUnbSSI2pFFS3mhPLwPbIi_7bgP0LXs7In_yuTzng2G7E0fZwjjxHD7LnFVlLoyZFHu76fbIA/?imgmax=800" width="244" height="209"></a> <a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjmHcVlKFsXYJGQvVD2mekiMF33qSZjZ2q5A_eStpLU6hrtV_L-wN1thp5eoRLuh7V8iRdvG_sM3Ko5_FCIUBCv_0seCHWS6xBMCTSRt2pPi-LBC1igiPymC-eEW-5wqyX-T45SVaV5mV4/s1600-h/ImageLoaderPhoneApp%25255B2%25255D.png"><img title="ImageLoaderPhoneApp" style="border-top: 0px; border-right: 0px; border-bottom: 0px; border-left: 0px; display: inline" border="0" alt="ImageLoaderPhoneApp" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgM770yTojx4Kvru5Moctx2D_RbR2v_OIMp3s43XiEYyevd17jZKdi01XtdRV9r7E1EGdiMSU34uQft5iQxpzPfHbQ6WStc0qYdrm9jJTSTEMiNLuWuUCL31S-5MmaCVKZFG9CTCA4NSLA/?imgmax=800" width="148" height="244"></a></p>
<p>Using the applications is a 3-step process.</p>
<ol>
<li>Run the phone app within the emulator, but don’t press anything. Just close the app immediately. This must be done first, to load the app onto the emulator, so that the desktop program can then load data into it.</li>
<li>Run the desktop app, and select a folder for the camera roll and saved pictures folder. You can do one or the other, or both. (By default, it will recursively load all sub-folders as well, but you can un-check that option) After the folders are selected, just press the load button, and wait for the command windows that pops up to dissapear.</li>
<li>Run the phone app again, but this time press the button for the camera roll and saved pictures folder. These will now work, as the isolated storage should contain all of the images.</li>
</ol>
<h3>Wrap Up</h3>
<p>And that is all you should need to get your own images, even hundreds or thousands of images, onto the emulator. With this, there really isn’t any excuse for using the defaults anymore, so hopefully we’ll be seeing less of them in the store and on Twitter.</p>
<p>If anyone finds this useful, please let me know, as I would love to hear about it.</p> Jeffrey Harmonhttp://www.blogger.com/profile/07512475602963566955noreply@blogger.com1tag:blogger.com,1999:blog-6876994733118324449.post-84286013963427097042014-02-10T10:35:00.001-08:002014-02-10T10:35:15.173-08:00AdDuplex Pricing Update<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEii1-7POtlkfnVICLf1LQul1JJj43ATrcdb3T131J0ESev9JaBkekQprrjAT2mu-T_fwSaD_RMG84hWzpk4JJUj8XWwcYpYO6jR4JlTvFy_T6sjQJi0c1ekvUVM7xtE2fJNhrPom5oSg7M/s1600-h/image%25255B13%25255D%25255B2%25255D.png"><img alt="image[13]" border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhIYIgDHvixRwLGLAAgAzGMUu0fjLE01IMo7mzWb1mQxBGN506Kk0XEwVW4vpvUX7lyaLTHLxSaxn4HoDyyc-UR-4H1dKPH29mz2sXYba97vUrgJAgMtaMUlVhPszfZ1i-979dAXdPBPEw/?imgmax=800" height="118" title="image[13]" width="244" /></a></div>
<p>Most Windows Phone or Windows Store developers know about AdDuplex (which I am a Developer Evangelist for), and many use them to help promote their apps. They do this either by adding their control to their own apps (earning free ad impressions) or by simply purchasing ad impressions directly. For those doing the latter, <a href="http://blog.adduplex.com/2014/02/pricing-adjusted-based-on-your-feedback.html" target="_blank">their pricing just got a little better</a>, but has a higher starting point.</p>
<p>You used to be able to get 20,000 impressions for $60, which was a cheap way to test them out, but didn’t give you many impressions, and wasn’t very cost-effective. As some developers didn’t have enough money to purchase the larger packages though, they were stuck with this package, meaning they couldn’t get much for their money.</p>
<p>Adjusting to feedback, AdDuplex has replaced that package with a 50,000 impression package for $99. While costing a little more, it is still cheap enough for small devs to afford, and offers a 33% better CPM (cost per thousand)! It used to be $3, but is now $1.98.</p>
<p>Even better, if you currently have a published app with the AdDuplex control installed in it, they are currently giving a 20% discount on all ad packages, so be sure to check it out.</p>Jeffrey Harmonhttp://www.blogger.com/profile/07512475602963566955noreply@blogger.com0tag:blogger.com,1999:blog-6876994733118324449.post-38820439120632948542014-01-24T13:50:00.000-08:002014-01-24T13:50:03.846-08:00Windows Phone Dev Day - Cambridge, MA<h3>Jump-Start Your App, or Pass the Final Stretch</h3> <p>If you are a developer that is trying to finish up your app, and get it into the store, or if you are looking to start your very first app, Nokia wants to help. In just over a week, on February 1st, they will be hosting an event at the Microsoft offices in Cambridge, MA. There will be training, food and prizes, and while seats are limited, here is what you can look forward to:</p> <ul> <li><strong>12 PM DevCenter Submission Walkthrough</strong> (30 minutes): See just how easy it is to submit and publish an app worldwide <li><strong>12:30 PM Build an app in 30 minutes with App Studio</strong> (30 minutes): See how to build an app from an idea to publishable in 30 minutes, literally. <li><strong>1 PM - 1:30 PM Lunch</strong>: I’ll be providing food and snacks. This is when you think about what you need help with or when you should think of your app idea for App Studio. <li><strong>1:30-6 PM Hands-on time</strong>: The experts will be available to help during this time. They will be walking around helping and/or attending to requests for help.</li></ul><br /> <h3>Focus Can be the Most Important Part</h3> <p>While having plenty of Windows Phone experts around to answer questions, walk through the submission process, and demonstrate App Studio can be helpful, the most useful part of the day will quite possibly be the dedicated time to work on your app. Having a solid block of time to work on your app without distraction is extremely valuable, and can really help you crank through your to-do list, especially when there are people that can help your through any road-blocks that normally might slow you down.</p> <h3></h3> <h3>Links and Stuff</h3> <p>If you are interested in going, the link to signup is below:</p> <p><a title="http://www.eventbrite.com/e/boston-wpdev-day-tickets-10293069849" href="http://www.eventbrite.com/e/boston-wpdev-day-tickets-10293069849">http://www.eventbrite.com/e/boston-wpdev-day-tickets-10293069849</a></p> <p>Here is also a post from Lance McCarthy (the guy running the show) going into a little more detail.</p> <p><a title="http://nokiawpdev.wordpress.com/2014/01/21/get-it-in-the-store/" href="http://nokiawpdev.wordpress.com/2014/01/21/get-it-in-the-store/">http://nokiawpdev.wordpress.com/2014/01/21/get-it-in-the-store/</a></p> <p>I will be there helping out, and would love to see lots of people from the area show up, but as I said, seats are limited, so please don’t register unless you are sure you can make it.</p> Jeffrey Harmonhttp://www.blogger.com/profile/07512475602963566955noreply@blogger.com0tag:blogger.com,1999:blog-6876994733118324449.post-82301986780345365232014-01-10T15:30:00.001-08:002014-01-20T11:52:09.180-08:00Lessons From the AT&T Hackathon<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgBsREfeZLwQYN1png4B_DhtzTNGP9m5KSiUzMyFThYinFlH2tKJWEsaX8TSBKPO9EqVZ-zuZxMi7iGVvcCxp4AwGHgmOboPdbjumGihQDOY3GrBAYqNmqe9Zi1yiQtrYd90WiLyg91gxo/s1600/FlipCycleTileLarge.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgBsREfeZLwQYN1png4B_DhtzTNGP9m5KSiUzMyFThYinFlH2tKJWEsaX8TSBKPO9EqVZ-zuZxMi7iGVvcCxp4AwGHgmOboPdbjumGihQDOY3GrBAYqNmqe9Zi1yiQtrYd90WiLyg91gxo/s1600/FlipCycleTileLarge.png" height="155" width="320" /></a></div>
<p>Every year, AT&T hosts a hackathon and developer summit the weekend before CES starts. This year, I decided to enter, and created a team with Anthony Russell (@Anth0nyRussell), Kevin Wolf (@ByteMaster) and Alex Perez (@Aapg1102). We wanted to give Windows Phone a strong showing, but had a few challenges to work through.
</p>
<p>Below are some thoughts and lessons from what we went through.
</p>
<h3>
What to Write</h3>
<p>We had a few things to consider when planning out what to write for the hackathon. We didn’t want to waste our time writing something that was closely tied to custom hardware, and would end up being discarded after the event, but in the wearables category, it is hard to get a winning entry otherwise. We also felt that we had a disadvantage on the hardware front, as most wearable tech is made for iOS and Android, with no support for Windows Phone. A clear strength we felt we had though, was productivity in building the actual app. C#\MVVM and Visual Studio can fly through app development faster than xCode or Eclipse could hope to. Adding in an Azure back-end was also an easy addition that, while available for other platforms, probably wouldn’t be used much at the competition, and could be a big differentiator.
</p>
<p>Having said that, we looked at the hardware we had to work with (Kevin and Anthony were the two main hardware guys) and when talking about the SparkFun LEDs we had, we came up with the idea of sewing them to the back of a vest, and making turn signals out of them. That sparked various ideas about controlling them, and got us thinking about a cycling app to go along with everything. And trying to play up our productivity strengths, we wanted to really build out a full app, and not just some control prototype. And from that, the idea of FitBike was born...
</p>
<p>It would be a cycling app, like many other fitness apps, but would have a social aspect as well, allowing you to create routes that you can share with others, post times that you ride them so others can join, add friends to track what they’ve been up to and where there riding, and even gamifying the experience by having badges for completing various objectives. On top of that, the part of the app that runs while you are riding would be able to interact with multiple different pieces of hardware, including:
</p>
<ul>
<li>Pebble Watch – This could be updated with information about your ride performance (time, distance, avg. speed, etc) as well as alert you to upcoming turns in the route
</li>
<li>Custom LED Vest – This vest was custom built with SparkFun LEDs, allowing the rider to control turn signals on their back while riding at night
</li>
<li>Custom Gloves – These gloves are what control the vest, by letting the rider twist their wrist to the left or right to activate the turn signals.
</li>
<li>GoPro Camera – If one was mounted to the bike, it could be controlled as well by the gloves, allowing the rider to easily take pictures along the ride without distraction.</li>
</ul>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjXYgE_CqEPwtEwEWC9HcRM-yDA-NJr19MLflv0y-P59Phg1CrsIa59RnSDeGwlvNljsfF6EmMPdTNMd9tSQD0CKkzHJWJtdErm2mVSnmbNT3Vn2BJnpaM2FZPvEXRulOZmuaFu3w-TG8M/s1600/wp_ss_20140118_0002.png" imageanchor="1" style="float: left; margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjXYgE_CqEPwtEwEWC9HcRM-yDA-NJr19MLflv0y-P59Phg1CrsIa59RnSDeGwlvNljsfF6EmMPdTNMd9tSQD0CKkzHJWJtdErm2mVSnmbNT3Vn2BJnpaM2FZPvEXRulOZmuaFu3w-TG8M/s1600/wp_ss_20140118_0002.png" height="320" width="192" /></a></div>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjqsCxLNS_vC2uQDwzcB1erBrSqB5FsZFKoyi-7p5ZvDy_ysXlFdzyCyvzYvtifTIDWJRgcqvosT5VvoKKz4eknh6Uw5t-1qMNn7AcOXJHWEHY2ijC_Opa4e-vi10-CenM67pgN9yBxcbk/s1600/wp_ss_20140118_0001.png" imageanchor="1" style="float: left; margin-left: 3em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjqsCxLNS_vC2uQDwzcB1erBrSqB5FsZFKoyi-7p5ZvDy_ysXlFdzyCyvzYvtifTIDWJRgcqvosT5VvoKKz4eknh6Uw5t-1qMNn7AcOXJHWEHY2ijC_Opa4e-vi10-CenM67pgN9yBxcbk/s1600/wp_ss_20140118_0001.png" height="320" width="192" /></a>
<br />
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<h3>
How to Code It</h3>
<p>Once we knew what to write, we started planning out who would be in charge of the various tasks, and how the code itself would be structured. I can’t stress just how helpful this was to enabling us to quickly execute on our plans, as we had an ambitious scope for 24 hours. While everyone had various strengths, many of them overlapped, so it wasn’t always easy to decide who did what, but we ended up breaking the basic tasks as follows:
</p>
<strong>Kevin</strong>: Hardware setup and coding, as well as Azure setup<br />
<br />
<strong>Anthony</strong>: Cycle route creation and tracking<br />
<br />
<strong>Alex</strong>: Visual design, and initial screen creation<br />
<br />
<strong>Myself</strong>: Overall app structure (allowing shared code between Win8 and WP8), data flow and Nokia Imaging SDK.<br />
<p>When we met in person in Vegas, we started going through the app in more detail, picking the feature list we thought we could create, and drawing out diagrams showing how the user would move through the app. This diagram was extremely helpful for assigning tasks further, and especially for Alex, who was able to just blow through creating gorgeous screens for each page in the diagram. Also, I had come up with the general coding structure we would use within the app, and went through that with the team, so we were all in agreement with where the various different parts of the code would sit, and how they would be formatted. (We even went over things such as how to case variables, where I was out-voted, having to change to use an underscore for private member variables, instead of just lowercasing it.)
</p>
<p>All of these things gave us a huge head start, as we knew exactly what to do once we started, and didn’t have to waste any time with discussions. I immediately started creating the initial solution in Visual Studio, with a project for the phone app, Windows 8 app, and a core PCL of shared code; as well as installing all required libraries such as MVVM Light (PCL), Azure Mobile Services (PCL) and the Nokia Imaging SDK (WP8 only). Kevin started setting up everything in Azure, including any tables we would need, and creating the base classes that handled talking to Azure. Anthony started a new phone project where he could create the code and UI for creating routes, as he knew exactly how he would need to plug it in to the main app once it was ready. And as stated earlier, Alex was able to quickly create awesome looking XAML pages for each of the screens we had laid out earlier, and start on the various graphics we would need in the different parts of the app (logos, icons, badges, etc). And once Kevin finished creating all of the tables, I was able to quickly create the view models that represented them, giving us a fairly stable core of the app within a couple hours of starting.
</p>
<h3>You Can’t Do It All</h3>
<p>After that, and despite out best efforts (as with all projects), simple tasks started taking longer than planned, and schedules started to slip. While the big points that we had discussed really came together well, the subtle parts of each area needed more discussion throughout the event. Even worse, the simple things that we had all done before (and we therefore didn’t allot much time to) just wouldn’t work, and often took hours to fix. Getting cropping and resizing in the Nokia Imaging SDK working with my UI code was causing me grief, storing and retrieving images in Azure BLOB storage was taking Kevin longer than planned (as well as a NuGet referencing issue), and Anthony was having trouble getting points tapped on a map to sync up properly onto the street.
</p>
<p>With the broad scope of our project plan, there were enough little issues piling up, and we soon realized we would need to start cutting some features. We had planned ahead for this as well, and knew what features were “nice to haves”, but not required, and started dropping those from the app.
</p>
<p>Probably the biggest mistake we made, as far as project planning, was to save the hardware code for the end. Since pretty much everything we were doing with hardware was just sending simple commands to controls them (which Kevin had done many times before), we assumed that would be a quick thing to integrate once everything else was up and running. The main hardware piece (the vest and gloves) of course wouldn’t work correctly when the time came to start integrating them in. We couldn’t figure out the cause, but even once they were working, they weren’t very reliable. In the end, we realized that the extreme Bluetooth interference was causing most of the trouble. The hardware wasn’t used to having hundreds of people around all running various types of Bluetooth and other wireless technologies.
</p>
<h3>
One Last Surprise</h3>
<p>The last things that caught us by surprise, and really hurt our plans, was the announcement that there would be only 90 seconds for the presentation, and they would be very strict about enforcing it. The reason this affected us so much was that one of our initial strategies was to impress, not just with the hardware, but with how full-featured of an app we could create to go along with it. When you only have 90 seconds to explain and show-off everything though, breadth of features is not what will help. We ended up having to quickly fly through a summarized list of what it could do, and in the end, barely had any time to focus on the wearable side, which was what the focus of the competition was.
</p>
<h3>
What Was Learned</h3>
<p>Summing up the things that really worked were:</p>
<ul>
<li><strong>Know what you are going to write</strong>. I have done hackathons by myself where I didn’t know what I was going to write ahead of time, but working with other means that there is a lot more communication you don’t want to be doing on the clock. (My app <a href="http://www.windowsphone.com/s?appid=56f898b7-11fc-4c09-8b84-15592864209c" target="_blank">LockMapper</a> was actually created at a hackathon where I didn’t know what I wanted to do when I walked in.)</li>
<li><strong>Sweat the details</strong>. You may think that everyone on the team knows how to write an app, and may even all be on board with MVVM, but there are a lot of different ways to implement things, so again, at least get the basics figured out, and anything else you can think of that might be done differently by everyone (such as naming conventions, what does/doesn’t go in a view model, etc).</li>
<li><strong>Plan out the flow of your app</strong>. Even if you know what it will do, and roughly how it will work, actually drawing out the screens, and connecting them, on paper will help immensely in planning and execution.</li>
<li><strong>Plan out your roles</strong>. You don’t want two people working on the same thing, and you don’t want one person waiting on someone else. Figure out who is building what, and in what order various pieces need to be accomplished. That way, everyone knows what to work on while waiting for other pieces to be ready.</li>
<li><strong>Cut things out quickly</strong>. If there are things that aren’t core to your app, and are giving you trouble, cut them out immediately. If there is time, you can always add them later, but if there isn’t, you can never get the time back that you sunk into them.</li>
</ul>
Here are some of the things that caused us some trouble, and what we would do differently next time:<br />
<ul>
<li><strong>Keep a narrow scope</strong>. While I was aware of this general principal when first deciding what to write, I thought of the broader scope as a huge advantage for us if done right, but it ended up being a hindrance in the end. As a bonus point, finding out how long you will have to present as soon as possible is also extremely important.</li>
<li><strong>Figure out the most important aspects of your app, and do them first</strong>. While we tried to do this, the broad scope kept us from doing it well. We were in a wearable competition, and kept that piece until the end. Granted, Kevin (who did most of the hardware programming) was also doing the initial Azure coding (which I would have been waiting on), we should have prioritized any wearable coding much sooner.</li>
<li><strong>Have a presentation planned ahead of time, and decide who is going to do it</strong>. As programmers, we naturally think that the code is the most important part of a hackathon, but it isn’t. The winners almost always have a dead-simple idea that can be explained easily, and is easy to see its usefulness.</li>
</ul>
In the end, we didn't place in the top 3 for our category (although some judges we talked to said we were in the top 5), but ended up taking home 10K for the Nokia Windows Phone challenge, which was pretty awesome. The competition as a whole was a ton of fun, and many of us are looking forward to returning next year, but when we do, we will be a little wiser from our experiences this first time.Jeffrey Harmonhttp://www.blogger.com/profile/07512475602963566955noreply@blogger.com0tag:blogger.com,1999:blog-6876994733118324449.post-70068925143274521492014-01-08T22:12:00.001-08:002014-01-08T22:12:00.299-08:00Microsoft is Adding Carrier Billing to More Countries<h2>…but it will cost you… but it will probably help you</h2> <p>Carrier billing is quickly becoming more common throughout the world as an option to pay for things on your phone. Beyond convenience, the benefit to consumers is that those without credit cards are still able to make purchases. This is extremely important in countries where the vast majority of the population doesn’t even have them.</p> <h3>Microsoft is Working on It</h3> <p>Microsoft knows this, and knows that people with Windows Phone that can’t pay for apps aren’t as helpful to the developer community as those who can. Last year they tripled the number of carriers they could bill through to 53, across 53 markets, and have been adding gift cards as an additional option to even more markets. For some markets though, this comes with a cost, as carrier billing can have a higher transaction fee than credit cards.</p> <p>To help make it financially viable for them to keep expanding carrier billing to those markets, Microsoft is adding an additional 13.9% charge on top of the 30% they already charge, but only on purchases made with carrier billing in <a href="http://msdn.microsoft.com/library/windowsphone/help/jj206732(v=vs.105).aspx" target="_blank">these countries</a>.</p> <h3>This is Actually a Good Thing</h3> <p>While many people will complain about Microsoft charging developers even more, I think this is actually a great change for everyone. As said before, this allows Microsoft to add carrier billing to countries where it wouldn’t be financially viable before, and developers get a much larger pool of paying customers in those markets. Remember, that most of the people this fee will be charged against would not have been able to pay for ANYTHING before. Now they finally can. The extra money from those new paying customers will almost certainly dwarf the loss of the fee from those who would have paid regardless. And this has no effect on the majority of markets, or anyone who still pays with a credit card.</p> <p>Time will tell how much of an effect this will have, but I for one, am excited for it.</p> Jeffrey Harmonhttp://www.blogger.com/profile/07512475602963566955noreply@blogger.com0tag:blogger.com,1999:blog-6876994733118324449.post-25002144378815186952013-08-26T19:50:00.001-07:002013-08-27T05:31:18.655-07:00AdDuplex’s First Evangelist<p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjKXZXGRqBjhQKf-ZqQm33IavpJ-CjADE6o3RGH_dSGKOPAQPDYbvabkWsKwzd10e69pZoH3Tja21j7EV-j33v2TFTptgeZdxGkNxgfbQq4dHmMt-6NCk4RU7k2-ZDdZWIgq3HSqh7GfEQ/s1600-h/adduplex-logo-medium-white%25255B3%25255D.png"><img title="adduplex-logo-medium-white" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-top-width: 0px" border="0" alt="adduplex-logo-medium-white" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEheeCTIkgyZkVZ0nyJYhw6V-XnfukTiNZQXX7c1yIV1nodKpKCrdHCMauwnpAb2Tg6K-mWGo9U-fXcSYcGXzbhWvhwkZDLrFME2hc8ngFVyQCvr5zM0o10w4M8397lEr3dEU6jXjnJTYPI/?imgmax=800" /></a></p> <p>I am excited to announce that I have recently become the first developer evangelist for AdDuplex!</p> <h3>What is AdDuplex?</h3> <p>AdDuplex is a cross-promotion and advertising network for both Windows Phone and Windows 8.  They allow developers to display ads for other apps within their own, and in return, get their ads shown in other developer’s apps.  With the low return on ads, unless you have a large user base, this gives developers a great alternative for promoting their app, and growing their user base before trying to monetize.  Their slogan is appropriately “Advertise before you monetize.”</p> <p>If you have a new app that you want to jump-start, you can also purchase ads, which are both cheaper and more directed than any other option.  It is the only ad network that lets you target Windows 8 and Windows Phone (you can even target between WP7 and WP8), meaning that every time your ad is displayed, the viewer is only two clicks from installing it.</p> <h3>Why I Use AdDuplex?</h3> <p>I have been using AdDuplex for almost a year, since the day Memorylage was released on Windows 8.  My biggest focus at that point was trying to find a way to reach the early adopters of Windows 8, and not waste money advertising to people who didn’t have it.  AdDuplex was perfect for this.  And when I released the app for Windows Phone, back in February, AdDuplex again gave me the ability to target just those users who had Windows Phone 8.</p> <p>Between the yearly ad subscription that I purchased, as well as the ad impressions I receive from using the control in my apps, I have maintained a steady stream of clicks and downloads for both versions, without having to do any continued advertising elsewhere. (I obviously still did plenty of work at launch to reach out to web sites, create a web page/promo video etc.)</p> <h3></h3> <h3>What Does Being an Evangelist Mean?</h3> <p>My job is focused on two things: spreading the word about AdDuplex, and helping devs with any issues they might have using the service, or setting it up.</p> <p>I will be writing periodic posts about some technical aspects of using the service (setup, configuration, etc.) on both this blog, as well as the <a href="http://blog.adduplex.com/" target="_blank">AdDuplex blog</a>.  I will be promoting AdDuplex in-person at events I attend, and online as well, but will do my best to not be “spammy” about it.  <img class="wlEmoticon wlEmoticon-smile" style="border-top-style: none; border-left-style: none; border-bottom-style: none; border-right-style: none" alt="Smile" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWeQALwCGu5K4v1d_9JxL7dBwBiEwppN5kKeOpM4sRTvQhKBvz3pc8DF5GHFBCXvy0xkc_M2EPolP0ZVAVALpz2bSwMHd9SPGP-URUCGQDjuGtrBJ5HgS_ppQaXgB0V0yRGtMWW3orYTI/?imgmax=800" /></p> <p>If there are any questions about the technical stuff I write about, or AdDuplex in general, feel free to reach out to me on Twitter at <a href="https://twitter.com/jrharmon82" target="_blank">@jrharmon82</a>.  As I am not in any way the official support channel for them though, any other questions, such as account related ones, should be directed to AdDuplex directly.  They can be reached on Twitter at <a href="https://twitter.com/AdDuplex" target="_blank">@AdDuplex</a>, or through email at <a href="mailto:info@adduplex.com">info@adduplex.com</a>.</p> <h3>Learning More</h3> <p>Here are some links to more information:</p> <ul> <li><a href="http://www.adduplex.com">www.adduplex.com</a> </li> <li><a href="http://blog.adduplex.com/" target="_blank">blog.adduplex.com</a> </li> <li><a href="https://twitter.com/AdDuplex" target="_blank">@AdDuplex</a> </li> <li><a href="https://twitter.com/ailon" target="_blank">@ailon</a> </li> <li><a href="mailto:info@adduplex.com">info@adduplex.com</a> </li> </ul> Jeffrey Harmonhttp://www.blogger.com/profile/07512475602963566955noreply@blogger.com0tag:blogger.com,1999:blog-6876994733118324449.post-65308181905493370962013-07-18T06:25:00.005-07:002013-07-18T06:43:13.803-07:00Windows Phone Finally Alerts Devs About Being Featured<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj5ZNue7Puaue6AIOQmG0ZDsqk351PQ9NVedUkfS5osx6ozLcYDvZNvOQj9hxaaY81OsZbob08aowzuBzusE6AKtfPmbtFdgkZ7cGw-dgbow180jWMU5mOwESI8wVXqLapJR-rp_ZgKneo/s1600/featured_star.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj5ZNue7Puaue6AIOQmG0ZDsqk351PQ9NVedUkfS5osx6ozLcYDvZNvOQj9hxaaY81OsZbob08aowzuBzusE6AKtfPmbtFdgkZ7cGw-dgbow180jWMU5mOwESI8wVXqLapJR-rp_ZgKneo/s1600/featured_star.jpg" style="background-image: none; border-bottom: 0px; border-left: 0px; border-right: 0px; border-top: 0px; display: block; float: none; margin-left: auto; margin-right: auto; padding-left: 0px; padding-right: 0px; padding-top: 0px;" /></a></div>
<br />
<br />
The first time my app <a href="http://www.windowsphone.com/en-us/store/app/memorylage/39e034b8-c6b9-463a-92fc-cc9fef41e528">Memorylage</a> was featured in the Windows Phone Marketplace, I found out about it by my friend emailing me that he had seen it. The same thing happened when it was featured on Windows 8. While I was excited to see it featured, it was annoying that I had no way of knowing about it, and could easily miss it.<br />
<br />
I eventually found an app called <a href="http://www.windowsphone.com/en-us/store/app/app-spotlights/33695cc5-1f28-40f1-b5d3-e7f06f74820e">App Spotlights</a>, which actually tracks where and when your app is featured, all around the world, and can even notify you when it is. It's a great app, but still reactive.<br />
<br />
<h1>
Listening to Feedback, and Improving</h1>
As I, and I'm sure many other devs, had asked for some kind of a heads up when being featured, it was great to get an email this morning telling me that my app was going to be featured, when it would be, where it would be, and on what devices (I didn't even know that they targeted them differently). Below is the full text of the email.<br />
<br />
<span style="background-color: white; font-family: arial, verdana, helvetica, sans-serif; font-size: 12px;">Dear Windows Phone Developer,</span><br />
<br style="background-color: white; font-family: arial, verdana, helvetica, sans-serif; font-size: 12px;" />
<span style="background-color: white; font-family: arial, verdana, helvetica, sans-serif; font-size: 12px;">We have exciting news for you! Your app is scheduled to be featured in the Windows Phone Store on 20 July 2013. Each week, the Store features a fixed number of notable apps and games in prominent promotional spots for the day. Apps are featured in different combinations where they are visible based on market, placement, and device. These promotions help give great apps like yours the visibility and attention we think they deserve.</span><br />
<br />
<table cellpadding="2px" style="background-color: white; border-collapse: collapse; border: 1px solid rgb(112, 48, 160); color: black; font-family: arial, verdana, helvetica, sans-serif; font-size: 12px; width: 1280px;"><tbody>
<tr><td colspan="4" style="border: 1px solid rgb(112, 48, 160); color: #bd4eba; font-family: Calibri; font-size: 13px; padding-left: 10px; width: 1267px;">Targeted Promotional Markets for your Windows Phone 8 app(s)</td></tr>
<tr style="background-color: #9b4f96;"><td style="border: 1px solid rgb(112, 48, 160); color: white; font-family: Calibri; font-size: 13px; padding-left: 12px; width: 144px;">Title</td><td style="border: 1px solid rgb(112, 48, 160); color: white; font-family: Calibri; font-size: 13px; padding-left: 12px; width: 358px;">All phones</td><td style="border: 1px solid rgb(112, 48, 160); color: white; font-family: Calibri; font-size: 13px; padding-left: 12px; width: 359px;">Only phones from manufacturers other than Nokia</td><td style="border: 1px solid rgb(112, 48, 160); color: white; font-family: Calibri; font-size: 13px; padding-left: 12px; width: 359px;">Only Nokia phones</td></tr>
<tr><td style="border: 1px solid rgb(112, 48, 160); font-family: Calibri; font-size: 13px; padding-left: 12px; padding-right: 2px; vertical-align: text-top; width: 144px;">Memorylage</td><td style="border: 1px solid rgb(112, 48, 160); font-family: Calibri; font-size: 13px; padding-left: 12px; padding-right: 2px; vertical-align: text-top; width: 358px;"></td><td style="border: 1px solid rgb(112, 48, 160); font-family: Calibri; font-size: 13px; padding-left: 12px; padding-right: 2px; vertical-align: text-top; width: 359px;">Indonesia</td><td style="border: 1px solid rgb(112, 48, 160); font-family: Calibri; font-size: 13px; padding-left: 12px; padding-right: 2px; vertical-align: text-top; width: 359px;"></td></tr>
</tbody></table>
<br style="background-color: white; font-family: arial, verdana, helvetica, sans-serif; font-size: 12px;" />
<span style="background-color: white; font-family: arial, verdana, helvetica, sans-serif; font-size: 12px;">Many developers have also found it valuable to increase this exposure with their own marketing efforts. The blog post </span><a href="http://blogs.windows.com/windows_phone/b/wpdev/archive/2013/03/01/marketing-your-windows-phone-app-101-q-amp-a-with-resident-windows-phone-developer-bernardo-zamora.aspx" style="background-color: white; color: blue; font-family: arial, verdana, helvetica, sans-serif; font-size: 12px;" target="_blank">How to Market Your Windows Phone App</a><span style="background-color: white; font-family: arial, verdana, helvetica, sans-serif; font-size: 12px;"> can help you get started. You can also download the </span><a href="http://www.windowsphone.com/en-us/store/app/dev-center/2d3063c2-4b29-4e69-9c03-50b67b0e6aec" style="background-color: white; color: blue; font-family: arial, verdana, helvetica, sans-serif; font-size: 12px;" target="_blank">Dev Center</a><span style="background-color: white; font-family: arial, verdana, helvetica, sans-serif; font-size: 12px;"> app to track your app’s progress.</span><br />
<br style="background-color: white; font-family: arial, verdana, helvetica, sans-serif; font-size: 12px;" />
<span style="background-color: white; font-family: arial, verdana, helvetica, sans-serif; font-size: 12px;">Occasionally we need to modify the promotion schedule after we have sent a notification to you. We want you to be aware that this may result in a change to your app’s featured date(s).</span><br />
<br style="background-color: white; font-family: arial, verdana, helvetica, sans-serif; font-size: 12px;" />
<span style="background-color: white; font-family: arial, verdana, helvetica, sans-serif; font-size: 12px;">All of us here at the Windows Phone Store appreciate your support, and we can’t wait to see your next creation!</span><br />
<br style="background-color: white; font-family: arial, verdana, helvetica, sans-serif; font-size: 12px;" />
<span style="background-color: white; font-family: arial, verdana, helvetica, sans-serif; font-size: 12px;">Windows Phone Store Team</span><br />
<br style="background-color: white; font-family: arial, verdana, helvetica, sans-serif; font-size: 12px;" />
<br />
<table style="background-color: white; border-bottom-color: rgb(192, 192, 192); border-bottom-style: solid; border-bottom-width: 1px; color: black; font-family: arial, verdana, helvetica, sans-serif; font-size: 12px;"><tbody>
<tr><td style="background-color: #9b4f96; color: white; font-family: Calibri; font-size: 13px; height: 17px; padding-left: 5px; width: 1061px;">Learn more details about this program in the Frequently Asked Questions section below.</td></tr>
<tr style="height: 6px;"></tr>
</tbody></table>
<br style="background-color: white; font-family: arial, verdana, helvetica, sans-serif; font-size: 12px;" />
<br />
<div style="background-color: white; font-family: arial, verdana, helvetica, sans-serif; font-size: 11px;">
If you would like to provide feedback about this notification simply reply to this email.<br />
<br />
<div style="color: #ababab;">
Microsoft respects your privacy. To learn more please read our online <a href="http://www.microsoft.com/privacystatement/en-us/core/default.aspx" style="color: blue;" target="_blank">Privacy Statement</a>.<br />
<br />
If you would prefer to no longer receive this email click <a href="mailto:wpsappsteam@microsoft.com?subject=Unsubscribe%20-%20jeff@agiledatasoftware.com%20from%20Windows%20Phone%20Store%20Merchandising%20communications" style="color: blue;" target="_blank">here</a> or reply to this email with the subject line – “Unsubscribe <a href="https://email04.secureserver.net/webmail.php?login=1#" style="color: blue;" target="_self">jeff@agiledatasoftware.com</a> from Windows Phone Store Merchandising communications”.<i> Note: removal may take 48 hours.</i><br />
<br />
To set your contact preferences for other Microsoft communications, click <a href="https://profile.microsoft.com/ContactPreferences/securepages/default.aspx?&contactID=OeMJ1bx6N0kbLMdA6IUZYJ/0gfhOA0gngn6siDtSBFQAASUf&publisherID=10000&pubID=506" style="color: blue;" target="_blank">here</a>.<br />
<br />
Microsoft has no obligation to feature your application during this proposed campaign, nor an obligation to feature your application in any future promotional activities. Microsoft reserves the right, in its sole discretion, to make all final decisions regarding this campaign’s timing, frequency, placement, and application selection. This notification does not modify the Windows Phone Application Provider Agreement.</div>
</div>
<br style="background-color: white; font-family: arial, verdana, helvetica, sans-serif; font-size: 12px;" />
<br style="background-color: white; font-family: arial, verdana, helvetica, sans-serif; font-size: 12px;" />
<br />
<table style="background-color: white; color: black; font-family: arial, verdana, helvetica, sans-serif; font-size: 12px;"><tbody>
<tr><td style="background-color: #9b4f96; color: white; font-family: Calibri; font-size: 13px; padding-left: 5px; width: 1061px;">Frequently Asked Questions</td></tr>
</tbody></table>
<br style="background-color: white; font-family: arial, verdana, helvetica, sans-serif; font-size: 12px;" />
<b style="background-color: white; font-family: arial, verdana, helvetica, sans-serif; font-size: 12px;">Q1:</b><span style="background-color: white; font-family: arial, verdana, helvetica, sans-serif; font-size: 12px;"> I received an email that my app would be promoted in the Windows Store but it wasn’t there on the date promised. What happened?</span><br />
<b style="background-color: white; font-family: arial, verdana, helvetica, sans-serif; font-size: 12px;"><b>A:</b></b><span style="background-color: white; font-family: arial, verdana, helvetica, sans-serif; font-size: 12px;"> Sometimes we need to make last minute changes in the promotion schedule, and we are not able to pass this information on to the developers affected by the change. When this happens, we do our best to move these apps to the next available featured spot in the Store.</span><br />
<br style="background-color: white; font-family: arial, verdana, helvetica, sans-serif; font-size: 12px;" />
<b style="background-color: white; font-family: arial, verdana, helvetica, sans-serif; font-size: 12px;">Q2:</b><span style="background-color: white; font-family: arial, verdana, helvetica, sans-serif; font-size: 12px;"> How does Microsoft choose which apps to feature?</span><br />
<b style="background-color: white; font-family: arial, verdana, helvetica, sans-serif; font-size: 12px;">A:</b><span style="background-color: white; font-family: arial, verdana, helvetica, sans-serif; font-size: 12px;"> This </span><a href="http://blogs.windows.com/windows_phone/b/wpdev/archive/2013/01/31/how-to-get-your-app-promoted-in-the-windows-phone-store.aspx" style="background-color: white; color: blue; font-family: arial, verdana, helvetica, sans-serif; font-size: 12px;" target="_blank">blog post and video</a><span style="background-color: white; font-family: arial, verdana, helvetica, sans-serif; font-size: 12px;"> provides an overview of Microsoft’s promotion criteria.</span><br />
<br style="background-color: white; font-family: arial, verdana, helvetica, sans-serif; font-size: 12px;" />
<b style="background-color: white; font-family: arial, verdana, helvetica, sans-serif; font-size: 12px;">Q3:</b><span style="background-color: white; font-family: arial, verdana, helvetica, sans-serif; font-size: 12px;"> When Microsoft promotes my app, will I see an increase in my app’s download activity?</span><br />
<b style="background-color: white; font-family: arial, verdana, helvetica, sans-serif; font-size: 12px;">A:</b><span style="background-color: white; font-family: arial, verdana, helvetica, sans-serif; font-size: 12px;"> There are many factors that contribute to an app’s download activity. Microsoft cannot guarantee that being featured will result in an increase in download activity.</span><br />
<br style="background-color: white; font-family: arial, verdana, helvetica, sans-serif; font-size: 12px;" />
<b style="background-color: white; font-family: arial, verdana, helvetica, sans-serif; font-size: 12px;">Q4:</b><span style="background-color: white; font-family: arial, verdana, helvetica, sans-serif; font-size: 12px;"> Where in the Windows Phone Store will my app appear?</span><br />
<b style="background-color: white; font-family: arial, verdana, helvetica, sans-serif; font-size: 12px;">A:</b><span style="background-color: white; font-family: arial, verdana, helvetica, sans-serif; font-size: 12px;"> Your app will appear in the Store, Apps, or Games hubs in one of the following slots:</span><br />
<div style="background-color: white; font-family: arial, verdana, helvetica, sans-serif; font-size: 12px; margin-left: 21px;">
• Featured app of the day<br />
• one of eight Spotlights<br />
• one of three Icons</div>
<br style="background-color: white; font-family: arial, verdana, helvetica, sans-serif; font-size: 12px;" />
<b style="background-color: white; font-family: arial, verdana, helvetica, sans-serif; font-size: 12px;">Q5:</b><span style="background-color: white; font-family: arial, verdana, helvetica, sans-serif; font-size: 12px;"> Is it possible for Microsoft to promote my Windows Phone 7 apps?</span><br />
<b style="background-color: white; font-family: arial, verdana, helvetica, sans-serif; font-size: 12px;">A:</b><span style="background-color: white; font-family: arial, verdana, helvetica, sans-serif; font-size: 12px;"> While we do promote Windows Phone 7 apps, this notification program is for Windows Phone 8 apps only.</span><br />
<br style="background-color: white; font-family: arial, verdana, helvetica, sans-serif; font-size: 12px;" />
<b style="background-color: white; font-family: arial, verdana, helvetica, sans-serif; font-size: 12px;">Q6:</b><span style="background-color: white; font-family: arial, verdana, helvetica, sans-serif; font-size: 12px;"> For which countries do you notify participating developers?</span><br />
<b style="background-color: white; font-family: arial, verdana, helvetica, sans-serif; font-size: 12px;">A:</b><span style="background-color: white; font-family: arial, verdana, helvetica, sans-serif; font-size: 12px;"> We will be notifying participating developers when their Windows Phone 8 apps are promoted in Australia, Brazil, Chile, China, France, Germany, India, Indonesia, Italy, Mexico, Poland, Russia, Saudi Arabia, Spain, South Africa, Thailand, Turkey, United Arab Emirates, United Kingdom, United States.</span>Jeffrey Harmonhttp://www.blogger.com/profile/07512475602963566955noreply@blogger.com1tag:blogger.com,1999:blog-6876994733118324449.post-82187912247015748532013-02-11T20:39:00.000-08:002013-02-11T20:39:17.158-08:00Plugging Into Windows 8–Presentation SlidesI will be doing a talk at the Windows 8 Boston user group <a href="http://www.meetup.com/Windows8Boston/events/98805252/" title="Windows 8 Boston on Meetup.com">tomorrow</a>, February 12th. The slides that I created have a bunch of links, and a little bit of code, so I wanted to place them online so that people can easily grab them.<br />
<br />
If you have any questions about anything presented, or want a copy of any of the code demonstrated, just send me a message on Twitter (@jrharmon82).<br />
<br />
<a href="https://skydrive.live.com/redir?resid=89B78560E756FA16!31898&authkey=!APDc9gYegsLPxdI">Slides</a>Jeffrey Harmonhttp://www.blogger.com/profile/07512475602963566955noreply@blogger.com0tag:blogger.com,1999:blog-6876994733118324449.post-11068759116690143882012-12-18T10:05:00.000-08:002012-12-18T10:05:34.707-08:00App Developers! Users Need Your Help!<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-K_u63XT_6TI-EkghK2dvZ191rAPE_MBVohjuYRZviTNHNruUDxXgk8HTGJy4mCrYdVSIib62i7TZ8d7bJJTkeUf8_6fefWUeHIIfE_sjQ6yP1UYlo3p4j-aDSpOVfDSrMuZ4ne7I3Fo/s1600-h/F1%252520key%25255B2%25255D.jpg"><img alt="F1 key" border="0" height="164" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhyIAdPRnFdrOscKw2aEXDt20FL8FRj4uGgbNHO34prQzjESALqFBL8ONavbTvW2uqvhFewjIaIKIEmCDu12s0UndP1lQSAEQyEtrmHOgrM-ovA8FXWkhA9RPlyMmSDeabERcQrHXYG2xo/?imgmax=800" style="background-image: none; border-bottom: 0px; border-left: 0px; border-right: 0px; border-top: 0px; display: block; float: none; margin-left: auto; margin-right: auto; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="F1 key" width="244" /></a><br />
I have been using Windows 8 since last December, when the Developer Preview was out. By the time the Consumer Preview was out, I had read all the articles about the (then) Metro design principles, learned how modern apps should be laid out, and about all of the new touch metaphors. I then designed my app <a href="http://www.memorylage.com/" title="Memorylage">Memorylage</a>, from the ground up, to properly make use of these features, and blend into the whole Windows 8 experience.<br />
<br />
The problem? While I may know and understand all of the new UI interactions for Windows 8; at this early stage, most of my users don't. And there aren't currently many signs pointing them in the right direction.<br />
<div align="center">
<br /></div>
<h4>
A Leap of Faith</h4>
In designing the new modern interface for Windows 8, Microsoft made a very important decision early on. They would create an interface that was as <b>efficient</b> as possible to <b>use</b>, but not as <b>easy</b> as possible to <b>learn</b>.<br />
<br />
This is an amazingly large gamble for something as big as Windows, and one that we won’t learn the outcome of for quite a while still. Can end-users really learn a new interface with no visual indicators? Do they want to?<br />
<br />
Regardless of the answers, the reality is that many new users are using Windows 8 for the first time, and as developers, our apps are one of the first experiences they have with it. Like it or not, our apps will often be judged for things that we have no control over.<br />
<br />
<h4>
</h4>
<h4>
Under-Utilized Features</h4>
Here are some of the biggest features that people were missing when using my app.<br />
<br />
<h5>
The Share Charm</h5>
<img align="right" alt="share-charm" border="0" height="244" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEigS8AbpFKgFw3AYvl4VPAHA6yNboGhBykNnQhRDi_d-YLQkVMST15gTuJBRfXZvKTKMqzxOrH0pCqmxaf8T2vesCZowiPBRtoEwlOvgbvFUSJg9Tg1lofElS22IQTwzDQ0liFDuRhfhD8/?imgmax=800" style="background-image: none; border-bottom: 0px; border-left: 0px; border-right: 0px; border-top: 0px; display: inline; float: right; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="share-charm" width="99" />
The charm bar is one of the more divisive UI elements in Windows 8, and one of the less obvious for new users to really understand. They often don’t realize that it is context-sensitive to whatever app you are in, and think it is just for the OS itself.<br />
<br />
Looking through usage data from my app, I saw that from the custom collages being created, over 38% of those were saved, but only 1.5% were being shared. There may be a bit of preference towards saving an image over sharing it directly, but with numbers that drastic, it is obvious that the share charm is not being well utilized.<br />
<br />
For those apps using the search or devices charm, be ready for the exact same issue.<br />
<br />
<h5>
Selecting Images</h5>
With touch, the way to select an item is to do a cross-swipe, where you swipe perpendicular to the direction of panning. So if your content scrolls horizontally, you would swipe up or down on an item to select it. This works great, as it allows you to quickly select or interact with an item, such as tapping to view full-size.<br />
<br />
Unfortunately, it is not as obvious to the end user, and since you must select an item before being able to create a custom collage, many people I talked to didn’t find out about this feature, or considered it a “hidden” feature that they found eventually.<br />
<br />
It also was not obvious to many that you could select multiple items without any special keys, which you would normally need in a program such as File Explorer.<br />
<br />
<h5>
Semantic Zoom</h5>
Semantic zoom is one of the new navigation methapors that Windows 8, and can work really well to quickly jump around through large lists. And while it may be fairly easy to discover on touch, it is much less obvious for a mouse and keyboard.<br />
<br />
Very few people know about the Ctrl/- keyboard shortcut, or to hold Ctrl while scrolling with the mouse wheel. I use this all the time in my app, and people are always impressed when I show it to them, but for all the people I have shown the app to in person, <strong>not a single person has ever found it on their own.</strong><br />
<h5>
Navigating From the AppBar</h5>
The three main functions of Memorylage are to view your photos as a series of dynamic collages, create your own custom collages from selected images, and to use the photo booth function to take new photos for a collage.<br />
<br />
Many people find photo booth and the creation of collages to be the biggest strengths of the app, but they are both accessed through the app bar, while you start out in the browsing mode. Since not everyone opens the appbar, and since the Custom Collage button is disabled until an image is selected, these are more features some people consider “hidden”.<br />
<br />
<h4>
A Gentle Nudge</h4>
The first thing I implemented, about a month ago, was a splash screen that displayed on the first run of the app, or after any update. This helped with a few different issues. It gave me a place to put a short getting started guide, let users know about new features being added, and gave me a way to get feedback from them through email or social media. This helped a lot, but is something that a lot of people don’t stop and read when first opening the app.<br />
<br />
<blockquote>
…provides a much less obtrusive replacement to the MessageBox.Show method we all know and love.</blockquote>
<br />
To further help users, I used the Popup control to give helpful tips within the app, at the exact time when someone might want to do those things. When first navigating to a new folder, it will let the user know about selecting images, and where the Custom Collage button is. When opening up the Photo Booth section for the first time, it tells them how to use it. For the share charm, I actually don’t mention it when first going to the Custom Collage page, but immediately after the first time they save a collage.<br />
<br />
The Popup control is a great new addition to WinRT, and provides a much less obtrusive replacement to the MessageBox.Show method we all know and love. In a future post, I will show the code I used to create a static class that closely resembles the MessageBox.Show method, allowing you to simply pass in the text you want to display, an optional heading, and an optional location. it will then create the Popup control, with its content, and display it. All in a single line of code.<br />
<br />
The last change I made, to further highlight the Custom Collage and Photo Booth sections of the app, was to move those two buttons to a top app bar. I have noticed that most buttons that navigate to s new section of the app are located in the top appbar, instead of the bottom. Also, by having the two buttons separated, it highlighted them as well, making them easier to spot.<br />
<br />
<div align="center">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiFNQOKot8Qts_vkS_uF2NgYON3z5gOSf8DSMVNIPZ8ejfj1yUhTpGxRJ5H6hyrVoUO6Vc99SAPAKm-cr1jSHl4W1JvSxwbAXK3WeepIz6bYm9HN2_xrB0m62EWiv7HDBbJhQpRCEcrATY/s1600-h/BandScreenShot%25255B2%25255D.png"><img alt="BandScreenShot" border="0" height="139" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjAaQwidUbRrEhLHZzVypc1hTUgaNBl4kyOhEOKaLW-s6mA_Idy9gw4qTxSMYDbee3LGeJsXbJNADAOxohBMZZ1ALHFkVnd-iOeTvNGDnTi31SY-pihXYtol25sYOd1OIg7E0PhYvnfFf8/?imgmax=800" style="background-image: none; border-bottom: 0px; border-left: 0px; border-right: 0px; border-top: 0px; display: block; float: none; margin-left: auto; margin-right: auto; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="BandScreenShot" width="244" /></a></div>
<div align="center">
The navigation options in a custom top appbar<br />
<br /></div>
<h4>
Store App Restrictions</h4>
It’s not just hidden features that confuse users, but also some of the store app restrictions that don’t apply to the apps people are used to.<br />
<br />
One of the most requested features for Memorylage, is the ability to view images outside of the Pictures library. I have gotten many bad reviews solely due to my apps inability to do just that. This is of course a basic restriction on apps within the store, but the problem is that the average user doesn't know this. This was made abundantly clear when I got a scathing 1-star review, saying how the app didn't support the synced SkyDrive folder on the desktop, and therefore wasn't even worth trying.<br />
<br />
I ended up writing a <a href="http://www.agiledatasoftware.com/memorylage/picturelibrary.html" title="Using SkyDrive and Folders Outside of the Pictures Library">short post</a> on the Memorylage website, and made use of the splash screen to point all of my users to it. Not only did it describe the restrictions the app had, and why it wasn't my fault, it helped inform them about how to fully utilize the Pictures library. Many people don’t realize that you can add extra locations to it, and all of the files don’t actually have to reside there. This is especially useful when adding in synced folders from SkyDrive.<br />
<br />
Luckily, the user who wrote the 1-star review emailed me as well about the lack of SkyDrive support, and after explaining how it worked, and pointing him to the article, he actually revised his review and gave me 4-stars.<br />
<br />
<h4>
What is Microsoft Doing?</h4>
<blockquote>
…they want to leave a fun element of “discovery”…</blockquote>
<br />
The big question remaining though is what Microsoft is doing to help with this. I can’t describe the disappointment at seeing their “training” video during a new account creation. This was supposed to be their way of teaching users the new interface, but it simply shows swiping in from a single side, and moving to a single corner with the mouse. It doesn’t show what any of the other sides or corners do, or even describe what the first side/corner actually does.<br />
<br />
I guess they want to leave a fun element of “discovery” for the user, but from what I have seen of many people trying it on their own; without some guidance from others, “discovery” is something many people will be missing out on.<br />
<br />
As more and more people start to use Windows 8, and learn how the various features work, these issues should start to be less frequent. In the mean time though, educating the users is part of the price of getting in early on a brand new eco-system, and is a pretty small one, if you are aware of it.Jeffrey Harmonhttp://www.blogger.com/profile/07512475602963566955noreply@blogger.com1tag:blogger.com,1999:blog-6876994733118324449.post-38792598769853600252012-12-01T15:44:00.001-08:002012-12-28T20:48:26.356-08:00Recursive Folder Thumbnails<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhUixgKvXEGjbe0wYo3-KppsHlrI4dbuLXWQhy7F_298SQaOgbvTScW79U0kVSsW4mRcDBXONclfl-MpcPrIaGN2pK3K5rgsti8Me5WCXrNIMDEa3Jz2szOYWSmRFK-Rz0bpIjoMp7G0RQ/s1600/Recursive+Folders.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="160" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhUixgKvXEGjbe0wYo3-KppsHlrI4dbuLXWQhy7F_298SQaOgbvTScW79U0kVSsW4mRcDBXONclfl-MpcPrIaGN2pK3K5rgsti8Me5WCXrNIMDEa3Jz2szOYWSmRFK-Rz0bpIjoMp7G0RQ/s320/Recursive+Folders.png" width="320" /></a></div>
<h4>
Thumbnails Everywhere</h4>
One of the best new features of WinRT is the thumbnail API. This allows you to very easily grab thumbnails of any type of item in the file system, such as an image, a song, a folder, or any other file type, and Windows will handle returning a proper thumbnail for it.<br />
<br />
For images, this is even more useful, as it will take care of positioning and cropping the image correctly, so that an image of any aspect ratio or rotation can be returned in a standard size. It always crops towards the top center of an image, as that is where the most important part of an image usually is, especially if it is of a person. This is actually a very important part of how images in <a href="http://www.memorylage.com/" title="Memorylage">Memorylage</a> are displayed.<br />
<br />
Here is a great article about how to use the API for any type of thumbnail: <a href="http://msdn.microsoft.com/en-us/library/windows/apps/hh465350.aspx" title="Guidelines for thumbnails">Guidelines for thumbnails (Windows Store Apps)</a><br />
<h4>
A Minor Annoyance</h4>
For folders, the API will look for a file directly within it, and use that to an appropriate thumbnail, such as an image for an image file, or album art for a song. The problem is that the file must be <strong>directly</strong> inside the folder, and not within a sub folder. If you have a folder with many sub-folders (all containing images), but no files directly inside it, then no thumbnail is returned.<br />
<br />
For the initial version of Memorylage, I used the GetThumbnailAsync() method as-is, and just displayed a default image if there wasn’t a thumbnail found. This worked well enough in most cases, but it always bothered me a little seeing defaults in places that they really weren’t needed. After seeing it mentioned in reviews of the app, and in emails from people using it, I decided to finally fix it up.<br />
<h4>
The Code</h4>
Fixing this was actually fun, because it was one of the few times outside of a classroom that I actually got to use recursion. I also made it an extension method, so that it can easily be used in place of GetThumbnailAsync().<br />
<span style="font-family: Consolas; font-size: x-small;"> </span>
<br />
<pre class="brush: csharp">public static class FolderThumbnailExtensions
{
public static async Task<StorageItemThumbnail> GetThumbnailRecursiveAsync(this StorageFolder inFolder,
ThumbnailMode mode, uint thumbWidth, ThumbnailOptions options, bool tryThisFolder = true)
{
//try to get the thumbnail directly from the folder
if (tryThisFolder)
{
var thumb = await inFolder.GetThumbnailAsync(mode, thumbWidth, options);
if (thumb != null)
return thumb;
}
//get the sub-folders of the input folder, and return null if there are none
var folders = await inFolder.GetFoldersAsync();
if (folders.Count == 0)
return null;
//try to find one with a thumbnail
foreach (var subFolder in folders)
{
var thumb = await subFolder.GetThumbnailAsync(mode, thumbWidth, options);
if (thumb != null)
return thumb;
}
//if we reached this point, none of the sub-folders had a thumbnail, so call this method
//recursively for each one until you find one
foreach (var subFolder in folders)
{
var thumb = await subFolder.GetThumbnailRecursiveAsync(mode, thumbWidth, options, false);
if (thumb != null)
return thumb;
}
return null;
}
}
</pre>
<h4>
Conclusion</h4>
WinRT shows a lot of promise, and seems to get a lot of things right. It is still new though, and has quite a few holes compared to Win32 (as does the XAML side compared to WPF). In the mean time though, many of the things are easy to implement yourself, and plenty of other people are doing so already.<br />
An excellent example that everyone should check out is the <a href="http://winrtxamltoolkit.codeplex.com/" title="WinRT XAML Toolkit">WinRT XAML Toolkit</a>.<br />
<br />
Let me know if you have found any others.Jeffrey Harmonhttp://www.blogger.com/profile/07512475602963566955noreply@blogger.com0tag:blogger.com,1999:blog-6876994733118324449.post-25859207843976066142012-10-24T21:02:00.000-07:002012-10-29T15:57:08.333-07:00Windows 8 Doesn’t Want Your App. Try Again Later[Update 3: And it finally passed certification and is now in the <a href="http://apps.microsoft.com/webpdp/app/memorylage/269b17da-9475-4339-9786-2131c9880d52">store</a>! (Oddly enough though, I didn't actually change any code between the last release and this one.) Thanks to everyone that checked this post out and commented here or elsewhere, and thanks to the people at Microsoft that helped me through a lot of the issues. While I wrote this to point out the flaws in the overall certification process, and ways it could improve, the individual people that I worked with were always wiling to go out of their way to try and help. As mentioned below, they already had this escalated it internally before this was posted.]<br />
<br />
[Update 2: A lot of people are commenting on various sites about how it is my fault that my app failed, as it was due to problems with my code. I agree completely, but the point of the article is not that Microsoft failed my app, but that <b>they don't clearly explain why they failed it</b>, which turned me failing once or maybe twice to failing 6 times.]<br />
<br />
[Update: I just went to the Microsoft Store this morning to pickup a Surface tablet (so I could test on an ARM computer), and after getting my pre-order slip over the weekend, and being told that they open early at 8, I show up at 7 and am first in line! At 7:30 though, I overhear that Microsoft sent out an email yesterday saying that they couldn't open the store until their normal time of 10. I have a job, so I left Surfaceless and un-happy. #NotHowToLaunchAMajorProduct]<br />
<br />
To start, let’s get one thing straight: Microsoft desperately <b>needs</b> apps in its store. If not only for Windows 8, especially for Windows RT, which can only run apps from there. It also <b>wants</b> as many apps in there as possible, and has been very active in courting and helping developers to write app for it. For the most part, I think they have done a great job, as the tools, documentation and examples are excellent. Where they really fall down though is in the last mile: app submission.<br />
<br />
I first submitted my app, <a href="http://www.memorylage.com/" title="Memorylage">Memorylage</a>, to the store on August 29. Since then, it has failed validation 6 times, and I still don’t know what is causing the failure. Below, I talk about what I have gone through in the past 10 months, trying to get my app ready, but since it is a little long winded, I have a “Short Version” further down if you want to skip to there. (I won’t blame you) Also, please subscribe to my blog if you find it interesting.<br />
<br />
<h1>
The Long Version</h1>
<h4>
Getting Ready For Submission</h4>
Memorylage has been in development since December, back when there was only the Developer Preview to use. It was sorely lacking documentation and examples back then, but was enough to get familiar with what is a very different development experience from the Windows of old. By Consumer Preview, things had improved greatly, especially in the templates, and Memorylage was starting to take shape.<br />
<br />
Right around the release of the Release Preview, I attended a 3 day App Excellence lab that Microsoft hosted in their Waltham, MA office. As this was just a hobby, I had use up my vacation time to go, but it was a great way to get some focused development done, and meet some other developers. I also won the App X contest at the end, netting me a new Lumia 800 Windows Phone. Best of all though, I was able to schedule time with a Microsoft Field Engineer, flying in from Redmond, to review my app for early access to the store.<br />
<br />
The review involved a 60-point checklist we went though, which checked to make sure that the app met all aspects of their design guidelines, and really showcased how a Windows 8 app was supposed to work. He also dug deep into the performance and stability of the app, helping me find ways to improve the responsiveness, and give me ideas about how to improve it. There ended up being 3 issues for me to fix before he would grant me early access (2 of which I knew about before the meeting, but wanted input on), but a few weeks later (July 12th), I had resolved the issues and was granted an early access developer token.<br />
<br />
While I had the token, allowing me to submit to the store before almost anyone else, I really wanted to make sure the app was polished and feature complete before submitting, so I kept working on it to get it ready. I then went to a Hackathon, hosted by Microsoft at the Museum of Science in Boston, on August 18th where I won my second App X competition, netting me a Samsung Series 7 Slate, a $500 gift card and an XBox game. I also met plenty of people from Microsoft and elsewhere who were really interested in my app, and excited to see it in the store. They encouraged me to just hurry up and submit it, so I was really feeling good about the possibility of it taking off.<br />
<br />
I made up a list of things I felt I need to have ready before submitting, and quickly worked through them, eventually submitting to the store on August 29th. With only 500 apps in the store, and almost 2 months before general release of Windows 8, I was feeling pretty good about the work I had put into it. A day later though, I got the first of what would be many failure reports.<br />
<br />
<h4>
Where Things Fall Apart</h4>
Memorylage failed a day later for 4 reasons, and with the exception of the 1st, there really wasn’t much insight into what the issue was.<br />
<ul>
<li>Requirement 1.2: The website linked in the app and listing page was not finished </li>
<li>Requirement 3.2: The app crashes </li>
<li>Requirement 3.8: Performance </li>
<li>Requirement 3.10: Failed the Direct 3D test </li>
</ul>
I was surprised that they actually looked at the web site (I was planning on having it up by the time it made it to the store), but was happy to see that level of detailed review, as I figured it reflected well on the level of end-to-end quality that they were looking for. For the other failures though, I was left with quite a few questions. <br />
<ul>
<li>When does the app crash? <br /> <ul>
<li>At startup? </li>
<li>During a certain task? </li>
<li>Every time, or randomly? </li>
</ul>
</li>
<li>What performance problems are there? <br /> <ul>
<li>Does it startup too slow? </li>
<li>Does it suspend too slow? </li>
<li>Does a certain action hang or take too long? </li>
</ul>
</li>
<li>How did my app fail the Direct 3D test? <br /> <ul>
<li>It is a C#/XAML app that only uses standard controls, and should not have any DirectX requirements. </li>
<li>It was submitted as a neutral app, and accepted all DirectX levels </li>
</ul>
</li>
<li>Why did none of these failures occur when running the WACK (Windows App Certification Kit) on my own computer? </li>
</ul>
<br />
All of these are pretty basic questions that a developer would need to know to reliably be able to fix the issues that the store is finding. Staying positive though, I took this as an opportunity to really spend a few days doing nothing but polish work on the app. I went through every section and feature, cleaning up and speeding up anything I wasn’t 100% happy with. In the end, I felt confident that the app was truly store-ready, and that my app was better for the whole ordeal. That is, until it failed again for the same reasons! (minus the web site issue) <br />
<br />
<h4>
Bringing In Some Help</h4>
After trying a third time, releasing only for x86 (thinking there could be an issue of ARM devices, which developers weren’t able to test at that point), I couldn’t think of anything else to do with the vague results I was getting. So, I reached out to Bob, a developer evangelist that I met at the Hackathon at the Museum of Science. He asked me to send him my appx package, so that he and others could look at it themselves. and to post my questions in the support forums. I did both, and got many suggestions from various people, but everyone was basically just guessing, and telling me to try something and re-submit. Since access to the store was open by now though, each submission took longer and longer to come back.<br />
<br />
One person from the forums who worked at Microsoft actually had his own test store, and asked me to send him my app to run through certification there. I was excited to have someone looking closely at my app, who could give me a more detailed explanation of what was causing the failure, but no such luck. The app passed in his store, giving me no insight into the failures in the real store.<br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg9GCpT-n2q6KdEiMi1f33FWFqCuZSpRA5aUQFavEccT0ucOdfdUTe1RpRXUumx_hA_MR8ArDHs2420XyzQmUA3xOKmjKZb8ubOuKyHhf5vQy75k0DNpEmbYGZS7kuBRs7g6UqRaVTSMu4/s1600-h/test_store%25255B2%25255D.jpg"><img alt="test_store" border="0" height="182" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2lKb3pOcp3jsHnopXqgTIueiTFEQCVzniULU7_AHIq9mhmczAnxJOuh_PRl4wUeZ4cTJ_4_puwg4L1LuTr21cf4EavsRcu8oEIU2pUVXwGJLB1-CSvbmIIYH_psQvyG569dzjrv8M0po/?imgmax=800" style="background-image: none; border-bottom: 0px; border-left: 0px; border-right: 0px; border-top: 0px; display: block; float: none; margin-left: auto; margin-right: auto; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="test_store" width="244" /></a><br />
<br />
I was then given a link to Microsoft's <a href="https://getsupport.microsoft.com/Default.aspx?ccsid=634846153959727197">support site</a> (Windows store developers get two free questions that will be answered by someone at Microsoft, so definitely check it out) and while the person I originally talked to couldn't give me any answers, he escalated the issue to someone on the store team. It took a few days, but he did get back to me through email, and wrote the following:<br />
<br />
<blockquote>
Hello Jeffrey, </blockquote>
<blockquote>
<br />
I've reviewed this and found out what the concern was. I need you to resubmit the app to make sure that the issue has been resolved. I will be following the process of this submission so that I can verify at which stage the failure should pass. If it does not I will be following up with you to resolve. </blockquote>
<blockquote>
<br />
Thank you, <br />
-John</blockquote>
<br />
Without any indication as to what the issue actually was, he seems to be saying that it was something on their end, so I resubmitted the app, like he said.<br />
<br />
After 6 days of staring at this…<br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiT5FY2JZ_o05ic1d-jZSFfryqLo0wORMFwLHsuHZau1KRYCU6GEU50Ff-0CIMDXvsQ7Gd82xKnm5g8q64_x3RRv1coo3fW6vs5jkaF4ZCCW_RDDrEbPlqexg-iXXwuFSBw7cU5F80PFBo/s1600-h/Content%252520Compliance%25255B2%25255D.png"><img alt="Content Compliance" border="0" height="217" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi8PUSlNyo3aUmRxPQpU2fSNcSQ0FtWT_UOC9wB6ehqqAYIDMvN4rp9KR9wi4pWrnJcdl4V671vak5QXWYkVGFXzoFGvA-9r9xvGpB443N7gzbL-Eui6GBKVxa9zMMgUYIcowHzesoFSbQ/?imgmax=800" style="background-image: none; border-bottom: 0px; border-left: 0px; border-right: 0px; border-top: 0px; display: block; float: none; margin-left: auto; margin-right: auto; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="Content Compliance" width="244" /></a><br />
<br />
…it fails with the same three errors.<br />
<br />
<h4>
Making Progress</h4>
I eventually get to talk to John on the phone. He tells me about the little information he can get from others on the store team, and even from some of the server logs used in testing. He says that it is failing on an ARM machine and a low-powered test computer, due to it crashing, and that because it crashes, the other two tests fail as well (which doesn't make sense to me). He still can't explain why the app appears to pass all tests in the technical compliance phase, but then fails in the content compliance phase though. His best advice to me is to try and test on the slowest computer possible, see if I can find any issues, and if that doesn’t work, just re-submit so that he can talk to certain people if it fails again.<br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhwII5GTSxKup1_0hVaoQAwjeTBGPVTKdWSjkTzpLBZij-gnNJFFFs_TZz3QvZb-Qjkr4NDCjWBSt-BlF7gO6Og617K8F3xbRwNZQWg9_db9pNtrtv9D7Bhvuz-VyxOSn437I94E9C7uUw/s1600-h/Store%252520Failure%252520Report%25255B2%25255D.png"><img alt="Store Failure Report" border="0" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhvXnSfULF3B2mkqVZbx07BBlgwCd-KVXLuca165z4uZcc6rKVpBcGBJwV58EM4tuwHUpo3mrZU_oF3iE7VKddcfnrkPFMqAwdfRjNpAa8c1amBRc4DMijwNfXDqe7bMhJfUDBceeV1KBE/?imgmax=800" style="background-image: none; border-bottom: 0px; border-left: 0px; border-right: 0px; border-top: 0px; display: block; float: none; margin-left: auto; margin-right: auto; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="Store Failure Report" width="244" /></a><br />
<br />
With the amount of time it took last time to simply fail again, I wanted to try one more time to find out what the issue was before re-submitting. I was already testing on a slow netbook, as well as an even slower VM, but apparently that wasn't enough. I then went to my VM settings and crippled it even more. I lowered to RAM to 1GB, slowed the CPU to roughly 1Ghz, and turned off 2D and 3D acceleration. Running the app didn't turn up anything new though, as it launched with no issues, and quickly as well. Thinking that there wasn't anything else I could do, I created a new app package to submit, and ran the WACK (Windows Application Certification Kit) one last time when… BINGO! It finally failed a test on my computer!<br />
<br />
<h4>
Closer, but Not Quite There</h4>
Memorylage failed the WACK for taking 2.46 seconds to suspend, with a limit of only 2. It also stated that the app used 1.5MB of IO during suspend, which was important, since my suspend code only saves a single string (the standard code from Microsoft for saving navigation history), meaning that there must have been contention trying to suspend while loading a folder. With this information, I had a fix in under a half hour, but for some reason the store kept hiding it from me in the error reports, keeping me from finding it.<br />
<br />
Since I was also had an un-easy feeling that the Microsoft Ad SDK I was using was causing the Direct 3D failure, I took that out as well and re-submitted. Both the performance and Direct 3D tests did indeed pass this time, but it was still crashing on startup.<br />
<br />
While I was heartened to see that 2 of the 3 failures were cleared up, that crashing failure (which I had NEVER seen myself) was starting to feel like it would keep me from ever getting into the store. After a few days of moping around, I read an article that mentioned that the app store had over 3,600 apps, and Windows 8 was only 3 weeks away from general release. This pushed to me take one final, and thorough look through ALL of my startup code.<br />
<br />
I literally yelled (scaring my wife) when I found the issue staring at me in the very first place I looked.<br />
<br />
In the constructor of App.xaml.cs was a call to CurrentApp<b>Simulator</b>.LicenseInformation that was left over from some initial test code I had written (all license code in use was using the correct object). Since the constructor normally never has any real code in it, and is usually collapsed, I had never looked before to see that it was left. Remembering that I had read about how calling that object will cause your app to crash when released in the store (but not when using it outside of the store) I knew that this had to be what was causing it to crash in the store every time. After a little more checking to be sure there wasn’t anything else, I re-submitted to the store, and waited <b>10</b> days until… it failed again!<br />
<br />
[<b>Edit:</b> I know that it was my fault for missing this line, but it would have been nice if it was caught by the WACK, or at least if the error report told me I missed it. It was actually listed in the top 5 reasons for failures in the store, so I am not the only one. Regardless, even after fixing it, it still failed.]<br />
<br />
<h4>
Another Valiant Attempt at Escalation</h4>
Ever since my third failure, I had been told by about 3-4 different people that my issue was being escalated internally, and that it should be resolved soon. This never actually yielded any results for me, but after emailing with Allan yet again (who has done everything he could to try and help), said that it would be escalated to his boss’ boss’ boss’ boss (a corporate VP). Needless to say, my hopes didn’t get too high.<br />
<br />
Conveniently though, I got the failure notice only a few hours before going to a live recording of <a href="http://www.dotnetrocks.com/" title="Dot Net Rocks!">Dot Net Rocks</a> (probably the most popular podcast on developing with Microsoft’s technologies) on the 17th. I got there early, and got to meet the hosts, Carl Franklin and Richard Campbell, and even show them my application (I brought the Samsung Slate I had won) and told them about what I had gone through so far. The guys were awesome, and really sympathetic about my issues, and actually quite mad about how Microsoft was handling things with the store. They said they would try and find someone that could help me out (their international tour was sponsored by Microsoft, and they constantly interview people from the company, so they have connections), but as this was just another promise of escalation, I kept my hopes low.<br />
<br />
I emailed them the next day though, just to follow up, and thank them for taking the time to talk to me. Richard emailed me back the next day saying that he yelled at one of the developer evangelists in New York about what developers are going through, and that hopefully the message would make its way to Steve Sinofsky (the president of the entire Windows division). He then said that there are <b>thousands</b> of apps stuck in the approval process, which is why it is so backed up. I didn’t think one more evangelist hearing about it would change anything though (I already had three tying to help me), and thought that would be it. A few minutes later though, I got another email from Richard saying that he thought about it again, and decided to email Sinofsky himself.<br />
<br />
This was definitely more than just a random “escalation”, so I started to get a little more hopeful, and Sinofsky even replied the next morning, saying that they would get back to me directly. This definitely got me hopeful, but yet again, I seemed to have been let down, as I have not heard anything more from him or anyone else about it. (In Sinofsky’s defense though, he does have a bit of an important launch in a couple days to focus on).<br />
<br />
<br />
<h4>
One Last Ongoing Hope</h4>
Allan has been keeping me up to date on what he has been doing on his end, and he just had me re-submit my app today, and forwarding me an email from someone saying that they would prioritize my app when it was back in submission. I still don’t know what was causing the last failure, and I haven’t heard back since, so I doubt I will make it in before launch, but I could be wrong.<br />
<br />
Either way though, nothing can the fact that the current approval process is hurting developers, and that is something that Microsoft cannot afford right now. I have already seen some progress as I have gone through my various submissions, and I am sure that in 6-12 months, none of these issues will exist, but I don’t think Microsoft can afford to wait that long.<br />
<br />
<br />
<h1>
The Short Version</h1>
<h4>
What I Did to Get Ready For Submission</h4>
<ul>
<li>I started working on Memorylage back in December, with the Developer Preview. I have been programming for Windows for 17 years, with C# for the last 6, so I wasn’t starting from scratch</li>
<li>I read through all of the their design and coding documentation, trying to really create something that showed off Windows 8’s features, and its design style</li>
<li>I re-wrote the app for the Consumer Preview when it was released, since a lot had changed, and the new version of Visual Studio wouldn’t even open up files from the Developer Preview anyways</li>
<li>I attended a 3-day App Excellence lab at Microsoft’s Waltham MA office, where Memorylage won the App X challenge at the end of it</li>
<li>I also setup a meeting with a Microsoft Field Engineer to review my app, so that I could get early access to the store. This process was extremely detailed, with a 60+ point checklist of criteria that my app needed to meet to get it. I had three things that I needed to fix when I first met him, but I passed the second time</li>
<li>I continued working on the app without actually submitting yet, because I wanted to make sure that it was fully polished and feature complete</li>
<li>I signed up for Microsoft’s 30-To-Launch program, which helps developers go through all of the steps necessary to get into the store. I already had gone through everything that they showed, but I figured it couldn’t hurt anyways, in case there was something new</li>
<li>I went to a Microsoft hosted Hackathon at the Museum of Science in Boston, where Memorylage again won the App X challenge at the end. This time, I netted a $1,200 Samsung Series 7 Slate with dock, a $500 gift card and an XBox game</li>
<li>I met several Microsoft people (and others) there that were encouraging me to submit my app to the store immediately, since they thought it was ready, and was something they wanted in the store</li>
<li>After another two weeks of polishing, I finally submitted my app on August 29th (almost a full two months before the release of Windows 8)</li>
</ul>
<br />
<ul> </ul>
<h4>
What Happened After Submission</h4>
<ul>
<li>The app failed for 4 reasons, 3 of which gave me no real idea of what caused the failure. The failures were for stopping responding (when did this happen?), performance (performance of what?), Direct 3D (I don’t use Direct 3D) and having an incomplete web site (I had it finished a day later)</li>
<li>I went through all of my code, cleaning up performance anywhere I could, and tried to fix anything that I wasn’t 100% happy with</li>
<li>I submitted again, and failed again for the same 3 reasons (minus the web site issue)</li>
<li>I emailed Bob, a developer evangelist who I met at the Boston Hackathon, who said that he would escalate the issue internally</li>
<li>I re-submitted again, but only for x86, thinking it may be an issue with ARM (since no developers had access to ARM to test with), but it still failed for the same reasons</li>
<li>I posted multiple thread in the support forums, asking for help with what I thought was an issue with the startup time (the performance failure) and the Direct 3D failure</li>
<li>Matt, who works at Microsoft and replied to the app startup post, asked me to send him my app, so he could test it in his own personal store. It passed all tests for him though, so I didn’t find out anything new</li>
<li>I went to Microsoft’s support site, and used one of my two free help requests to talk to someone directly through chat. They couldn’t help me, but escalated me to someone on the store team, who would get back to me via email</li>
<li>A few days later, I got an email from John, the person my support ticket was escalated to, saying that he thinks everything should be all set now, and to just re-submit. He never said what he thought was wrong in the first place</li>
<li>I resubmit and fail again for the same reasons. This time, it took 6 days to fail, since everyone had access to the store now. Each submission was now becoming a lot more costly as the release of Windows 8 was starting to get closer</li>
<li>John tells me that the failure is because I submitted a neutral app, which will be tested against ARM, but that can’t be it, because I had already tested as x86 only (the third submission). He also said that the Direct 3D failure was because I didn’t have a check against the feature level, and not because I used any Direct 3D features. This was also incorrect, as the documentation clearly states that you only need to check the feature level if using Direct X 10 or up</li>
<li>I get to talk to John on the phone, and he tells me that they couldn’t find out much information about my failures (even after pulling server logs), except that the app was apparently crashing during startup on a low-powered machine</li>
<li>I cripple my VM, so that it is SUPER slow, and run the WACK (Windows Application Certification Kit), which finally causes it to fail. The failure is due to taking too long to suspend, and the information it gives allows me to fix it in under a half hour. Why the store hides this information, and just gives a generic “Performance” error is beyond me</li>
<li>I also remove the Microsoft Ad SDK, since I have a feeling that it might be causing the Direct 3D failure</li>
<li>I re-submit, and wait another 5 days for it to fail again. The performance and Direct 3D issues were gone though, so it was just the crashing failure that was left</li>
<li>I find that my code has a leftover call to CurrentApp<b>Simulator</b>.LicenseInformation from initial development of the licensing code, and I know that this will cause the app to fail certification, but has no effect when running it on my own (making it very hard to catch) [<b>Edit:</b> I know that it was my fault for missing this line, but it would have been nice if it was caught by the WACK, or if the error report at least told me that I missed it. It was actually listed in the top 5 reasons for failures in the store, so I am not the only one. Regardless, even after fixing it, it still failed.]</li>
<li>I re-submit, and am hopeful that this will have fixed all of the issues, but after <b>10 days</b> of waiting, it fails again with the same crashing issue</li>
<li>Allan (another developer evangelist that had been helping me a lot) says that he has escalated my issue to his boss’ boss’ boss’ boss (a corporate VP), and will still try to get it through before launch (this is now the 17th of October, 9 days until launch)</li>
<li>I meet Carl Franklin and Richard Campbell from <a href="http://www.dotnetrocks.com/" title="Dot Net Rocks!">Dot Net Rocks</a>, at a live recording in Boston, who I got to show my app to, and tell about my issues. They say they will try to get someone to help, and initially just talk to some developer evangelist that they meet in New York about it, but Richard then decides to email Steven Sinofsky himself (head of the entire Windows Division) about the issue</li>
<li>Also, while at the Dot Net Rocks event, I meet Chris, who ran the App Excellence lab I went to, and he let me test Memorylage on his ARM tablet, and it worked perfectly, so the issues were not ARM based</li>
<li>Sinofsky actually responds the next day, saying that they will get back to me directly (I never hear back though)</li>
<li>I attend a webcast from Microsoft about common pitfalls of submitting to the store. The issue of calling the CurrentAppSimulator object is in the top 5 causes of failure, but thry still won’t catch that in any of the tests, or even tell you that was a cause for failure. The developer is left to figure it out on their own</li>
<li>John asks me to send him my app again, so he can look into it again (I haven’t heard back from him yet)</li>
<li>Allan tells me that I am on the docket for some critical store meeting, so they are working on it</li>
<li>Allan forwards me an email, asking me to re-submit my app, and they will prioritize the certification process</li>
<li>I am still waiting to hear back on that (it is now just past midnight on the 25th, with just under 24 hours until launch), but that was only yesterday, so I am actually confident I will hear back soon</li>
<li>So far, I have sent/received 131 emails back and forth with various people within Microsoft</li>
<li>I have given my app, and even my source code, to multiple people within Microsoft. To date, not a single one of them has been able to cause it to crash, or fail a single test. Every issue that I have figured out, I found on my own, but the store still fails it. How do you debug that?</li>
</ul>
<br />
<ul> </ul>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi8j_WLnQMwlxJ2WR4BStl2OpJyS06BDUJ0etdzVyGdvhHTOYhqwZL3SuW7GjUqTVab3Dmcvzj7U3MG0J84LO_5o5geBhULGyjbPMpve9aC-XwNh4Fw3DtPtXYeAFlrE-_TiTsAs4YWQUk/s1600-h/Store%252520Submission%252520History%25255B2%25255D.png"><img alt="Store Submission History" border="0" height="199" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiwe_ImXhetJhKfQHQvqgkvJ1EiBC7NR07HJPRSZtucR_GyROAD6HcJoIAMmN_ctoWaIWFQOJUI1Oh5L82BSM74j6Wcg_S1Na1hXjP_GyjO_Hg0k6hrC56jw5UMRLzDvMZF15kav8et-FE/?imgmax=800" style="background-image: none; border-bottom: 0px; border-left: 0px; border-right: 0px; border-top: 0px; display: block; float: none; margin-left: auto; margin-right: auto; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="Store Submission History" width="244" /></a><br />
<h1>
Conclusion</h1>
<h4>
What Went Wrong</h4>
There are many reasons why my app is still not in the store, and many things that could be improved. This is just a quick list of the ones I could think of. Hopefully, people from the store team will see this, and work on improving things. I have already noticed some improvement between the various submissions, but there is still a long way to go.<br />
<ul>
<li>Failure reports need MORE INFORMATION. Imagine hitting compile on a large program, and instead of the compiler saying that you missed a semi-colon, and on which line, it waits a week, and then just says that you have a syntax error. That is what the certification process feels like</li>
<li>Do not hide information from the WACK. If an app fails the suspend test, give the developer that information. It already creates a detailed report, so just forward that along.</li>
<li>If a test fails, especially a performance related one, or a crashing issue, let the developer know what architecture it failed on. As developers currently can’t test on ARM, letting them know that the app works great on x86 but fails on ARM would be really helpful. Same with if it passes on a normal machine, but fails on a very low-powered one</li>
<li>I still have no idea why the Ad SDK causes the app to fail the Direct 3D test. Everyone that I talked to says it shouldn’t, as it only uses a web viewer. If it does have an issue though, then developers should be notified, so they aren’t left guessing</li>
<li>Check for use of CurrentAppSimulator in the WACK. This was one of the top 5 reasons that apps failed validation, so it is a common mistake. Having the WACK check for it allows developers to find it before they even submit. At the very least though, tell the developer that it is the cause if it fails. None of my error reports gave any hints about it</li>
<li>When an app fails in the Content Validation phase, where there is an actual person looking at it, they should spend a few minutes giving as detailed a response as possible. Every response I got was a single sentence that told me nothing. It may take them a little longer per submission, but if it keeps developers from re-submitting 7 times, it will speed things up overall, and keep developers happier</li>
</ul>
<br />
<ul> </ul>
<h4>
What I Lost Because of This</h4>
Even if my app does get into the store before launch, or very close to it, there are already plenty of things that I have lost, which can’t really be recovered. Hopefully others have been luckier than me.<br />
<ul>
<li>Almost 2 months of marketing for my app, with very little competition. When I first submitted my app, there were only 500 apps. Now there are over 7,000</li>
<li>Almost 2 months of development time. I really couldn’t focus on adding new features when the current ones won’t pass. When dealing with a new market place like this, development time is precious, and 2 months is a lot</li>
<li>Another Samsung Series 7 Slate. The 30-To-Launch program is giving out a free slate to everyone who registered and got their app in the store before launch. Even though I submitted 2 months early, with a completed and polished app, I lose out on $1,200 worth of hardware</li>
<li>Extra marketing from winning the Boston Hackathon. Microsoft is offering to highlight Hackathon winners that have made it into the store, but the deadline in next Friday, and even if I make that, I have already lost the time over the past 2 months</li>
<li>Downloads and reviews. If I had been in the store all this time, I would already have built up enough of a reputation to help bring my app higher in the search results, instead of starting from scratch.</li>
</ul>
<br />
<ul> </ul>
<h4>
In Conclusion</h4>
This post went on waaay longer than I planned so I will be brief.<br />
<br />
I still think that Windows 8 is a great opportunity for developers, but as it stands, they are in for a world of hurt in trying to get through that last hurdle. As a long-time Windows developer, I really hope that changes soon.<br />
<br />
Also, I want to say that while the overall process may have been negative, every person that I talked to personally was always helpful, and willing to go out of their way to help me (especially Allan), and I don't want to put them in a negative light. It is just that Microsoft is a large company, and despite their best efforts, things still turned out the way they have.Jeffrey Harmonhttp://www.blogger.com/profile/07512475602963566955noreply@blogger.com67