<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Starin’ at the Wall</title><link>https://jdconley.com/blog</link><description>Software, startups, and life by JD Conley.</description><language>en-us</language><atom:link href="https://jdconley.com/blog/feed.xml" rel="self" type="application/rss+xml"/><item><title>Worry Less. Do More. Be Fearless!</title><link>https://jdconley.com/blog/worry-less-do-more-be-fearless</link><guid isPermaLink="false">tag:blogger.com,1999:blog-1741199026308686058.post-4836117030040205910</guid><pubDate>Thu, 18 Jul 2013 17:42:00 GMT</pubDate><description>&quot;we better have health insurance&quot; . . . &quot;peyton got hurt&quot; These are not the text messages you want to receive from your wife on Mother&#39;s Day, when you are four hours away from…</description><content:encoded>&lt;p&gt;&lt;a href=&quot;https://jdconley.com/blog-assets/imported/7f33a0235ce52e036af95ef2.jpg&quot;&gt;&lt;img src=&quot;https://jdconley.com/blog-assets/imported/485760479f72e63980d9e246.jpg&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;strong&gt;&quot;we better have health insurance&quot;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;. . .&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&quot;peyton got hurt&quot;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;These are not the text messages you want to receive from your wife on Mother&#39;s Day, when you are four hours away from home.&lt;/p&gt;
&lt;p&gt;Our daughter Peyton is four years old. She has a twin brother. They scare me daily. I assumed she broke her arm on the swings, her wrist on her bike or something like that. Nothing to worry too much about.&lt;/p&gt;
&lt;p&gt;About a month earlier I quit my awesome job at Disney Interactive making mobile games to dive in and cofound a startup,&amp;#160;&lt;a href=&quot;https://www.realcrowd.com/&quot;&gt;RealCrowd&lt;/a&gt;. A long time friend and cofounder Andy was at my parents&#39; house with me, and we were on our way to the bay area to meet with our other cofounders and live under one roof. We had been interviewed and accepted into the&amp;#160;&lt;a href=&quot;http://ycombinator.com/&quot;&gt;YCombinator&lt;/a&gt; (YC) Summer 2013 batch and decided to get a jump start by moving to silicon valley a few weeks before the program was scheduled to officially start.&lt;/p&gt;
&lt;p&gt;I&#39;ve been working from home the last few years after the last startup (Hive7) was acquired and consequently we are a very close family. The twins are a lot of work, and I try to support my wife Erika by being as flexible with my time as possible. I was already feeling the intense guilt of moving four hours away to Mountain View and relegating&amp;#160;my family to second priority for a few months.&lt;/p&gt;
&lt;p&gt;&quot;Is this startup going to be worth it? Of course this happened the day I&#39;m supposed to go to the bay area. Am I being too selfish?&quot; These questions haunted me.&lt;/p&gt;
&lt;p&gt;. . . and then the texts got worse.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&quot;she fell out of the window&quot;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A few weeks before this fateful Mother&#39;s Day we had moved into an affordable three story condominium in Stateline, Nevada (South Lake Tahoe area) with a great lake and mountain view, cutting our monthly rent in half and saving a bit on income taxes (there are no state income taxes in Nevada). I was cutting costs to help decrease my burn. Andy had planned to call that his second home while we hacked on RealCrowd, prior to being accepted into YC.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://jdconley.com/blog-assets/imported/7f4a3f079aed22e6c3fc013e.jpg&quot;&gt;&lt;img src=&quot;https://jdconley.com/blog-assets/imported/36d0d9e90929cce42c2f0018.jpg&quot; alt=&quot;&quot;&gt;&lt;/a&gt;I visualized every window of our three story home, floor by floor. Adrenaline started pumping. My heart rate increased. I had to&amp;#160;consciously&amp;#160;suppress&amp;#160;the panic building inside. I &lt;em&gt;knew&lt;/em&gt; the worst possible scenario had transpired. She had fallen through the screen&amp;#160;&lt;strong&gt;from the third story window&lt;/strong&gt; in the dining room, &lt;strong&gt;onto the asphalt driveway below&lt;/strong&gt; . I almost vomited. At this point I was oblivious to conversation people were trying to have with me.&lt;/p&gt;
&lt;p&gt;I immediately tried to call my wife. No answer. Again. No answer. Again. No answer. Then it dawned on me she was probably on the phone with 911, and that&#39;s why she had been texting.&lt;/p&gt;
&lt;p&gt;&quot;can she move? is she conscious?&quot; I replied. &quot;keep her still. it&#39;ll be ok. i&#39;m coming. love you.&quot; I added.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&quot;yes&quot;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;That was the most amazing &quot;yes&quot; I had ever received. It trumped our marriage proposal, every deal close, every VC commitment, every new customer.&lt;/p&gt;
&lt;p&gt;I looked up from my phone and told my parents I had to leave, Peyton had fallen out of a window at home. I jumped in the driver&#39;s seat of Andy&#39;s car and dragged him along with me to the hospital. He tried to make conversation to get my mind off of analyzing all the possible outcomes. He&#39;s a great friend. Due to the nature of the event, Peyton was life flighted to a hospital in Reno, NV. Erika had to find a ride as she couldn&#39;t go in the helicopter. It took her about an hour, and me about three hours to get to Reno.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Peyton had suffered multiple cervical spine injuries. Her neck was broken!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://jdconley.com/blog-assets/imported/6616a9ae27677b56a010ebd4.jpg&quot;&gt;&lt;img src=&quot;https://jdconley.com/blog-assets/imported/777f69da01829e802cdbb45d.jpg&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Those first few days after the event are a blur in my memory. Full of extreme sadness, happiness, worry, guilt, lack of sleep, and everything&amp;#160;in-between. Would she be paralyzed? Would she live? I researched statistics on these things. The stress of not knowing ate me alive. Peyton had a surgery to align her cervical spine and had a halo traction device applied. She woke up from anesthesia and the nurse did some tests.&lt;/p&gt;
&lt;h3&gt;Peyton could wiggle her fingers and toes and apply normal amounts of pressure!&lt;/h3&gt;
&lt;p&gt;She walked a few steps the next day. And then a few more. But we lived in a three story condo. There is no way Peyton could navigate the stairs. My sister took the initiative and managed a crew of our amazing friends and family, including Andy, to move us out of the home we had moved into just a few weeks earlier and into a storage unit. We&#39;d be taking our clothes to my&amp;#160;in-laws single story&amp;#160;house in the Sacramento area, and my family would move there for the treatment period, near to a cervical spine specialist at UC Davis Medical Center.&lt;/p&gt;
&lt;p&gt;For the next week I was not sure if I&#39;d be co-founding this company after all. Peyton would wake up in the middle of the night in extreme anger pulling at the bars and screaming to take the halo off of her. She was frustrated by her lack of mobility. She didn&#39;t want to try to walk. She was depressed and angry most of the time. &lt;em&gt;I couldn&#39;t leave her.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;But, thankfully, things got better. By the end of the first week she had adapted to her new mobility limitations, daily cleaning of the screws in her head (ouch), and started asking for help when she needed it. She stopped waking up in the middle of the night &lt;em&gt;every&lt;/em&gt; night. She would walk wherever she wanted to go. We took her to Chuck E Cheese&#39;s.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://jdconley.com/blog-assets/imported/9706cb7d763ab922080fc0a7.jpg&quot;&gt;&lt;img src=&quot;https://jdconley.com/blog-assets/imported/d7192a4ef57536034caff04f.jpg&quot; alt=&quot;&quot;&gt;&lt;/a&gt;At the end of week two I knew Peyton would be able to deal with the halo, and my amazing wife encouraged me to not pass up the great opportunity that is RealCrowd and YC.&lt;/p&gt;
&lt;p&gt;Peyton is still wearing the halo, and will be for a total of 12 weeks. I see her on weekends. My little girl is &lt;strong&gt;alive&lt;/strong&gt; . But life is not normal. She has a very serious risk of infection (in fact she&#39;s on antibiotics now for one), a risk of losing traction, a risk of her skull being punctured by the screws. She can&#39;t get her vest wet. She can&#39;t run and jump and tumble. She has a twin brother that gets to do all these things. She gets frustrated every day. At the end of dealing with all of that we&#39;ll know if she healed or if we have to do more invasive surgery to fuse some bits together. I worry about her constantly.&lt;/p&gt;
&lt;p&gt;Will anyone use our product? Can we close that deal? Will our business keep scaling? Will we meet our goals? Can we hire that person? What if ... ? These questions no longer keep me awake at night. I do not fear the outcome. I keep pressing on. We&#39;re building a business, not dodging death. Perspective is everything.&lt;/p&gt;
&lt;h3&gt;Worry Less. Do More. Be Fearless!&lt;/h3&gt;
&lt;p&gt;Oh, and yes, we did have health insurance.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Public service announcement:&lt;/strong&gt;&amp;#160;If you have a window that&#39;s near the floor, make sure nobody can pass through the screen. Many state/local building codes say openings on the 2nd story or higher that are less than 24&quot; off the floor must not permit a 3&quot; sphere from passing through (aka, you need bars on the windows or a way to restrict them from opening). Ironically this can conflict with fire codes, so, your mileage may vary. This applies to deck and stairway railings as well. If you are a landlord, check out your rental properties and make sure they&#39;re compliant too.&lt;/p&gt;
</content:encoded><category>fear</category><category>startups</category></item>
<item><title>Install node.js in 10 Seconds or Less</title><link>https://jdconley.com/blog/install-nodejs-in-10-seconds-or-less</link><guid isPermaLink="false">tag:blogger.com,1999:blog-1741199026308686058.post-4679098985155157274</guid><pubDate>Mon, 01 Aug 2011 22:00:00 GMT</pubDate><description>I&#39;ve been playing around a bit with node recently. One thing it&#39;s quite good at is quickly bringing up a developer workstation. You can just run a quick command line to have…</description><content:encoded>&lt;p&gt;I&#39;ve been playing around a bit with &lt;a href=&quot;http://nodejs.org/&quot;&gt;node&lt;/a&gt; recently. One thing it&#39;s quite good at is quickly bringing up a developer workstation. You can just run a quick command line to have the server running rather than futzing with config files, virtual directories, software installations, and such. When your team uses different development platforms (Linux, Mac, Windows) or your development environment is different from production, a bit of scripting makes it much easier to insure everyone is on a level playing field.&lt;/p&gt;
&lt;p&gt;I found myself having to remember too many commands when setting up node for my application on two different OSX laptops. I wanted to be able to quickly get node up and running for a non-privileged user account and with node modules installed locally for the application. This is ideal when you&#39;re working with multiple projects that may use different versions of node or different versions of modules.&lt;/p&gt;
&lt;p&gt;The key ingredient is the great version management tool called &lt;a href=&quot;https://github.com/creationix/nvm&quot;&gt;nvm&lt;/a&gt; (Node Version Manager). It lets you easily download, compile, and associate a version of node with a particular terminal session. Combined with &lt;a href=&quot;http://npmjs.org/&quot;&gt;npm&lt;/a&gt; (Node Package Manager), making a setup script for an application is nice-n-easy. I whipped up this little script for a recent prototype project. Copy and modify as desired.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#!/bin/sh

#A script to setup the node environment using nvm and npm.
#This is intended to be run on developer workstations. 

#Check for well known prereqs that might be missing
hash git 2&amp;gt;&amp;amp;- || { echo &amp;gt;&amp;amp;2 &quot;I require &#39;git&#39;.&quot;; exit 1; }
hash make 2&amp;gt;&amp;amp;- || { echo &amp;gt;&amp;amp;2 &quot;I require &#39;make&#39;.&quot;; exit 1; }
hash python 2&amp;gt;&amp;amp;- || { echo &amp;gt;&amp;amp;2 &quot;I require &#39;python&#39;.&quot;; exit 1; }

#Clean up old stuff.
rm -rf ~/.nvm
rm -rf node_modules

#Download, source, and update nvm&#39;s package list
git clone git://github.com/creationix/nvm.git ~/.nvm
. ~/.nvm/nvm.sh
nvm sync

#Install latest stable version of node
#Change &#39;stable&#39; to a version number to install a specific node
#See `nvm help` for more info
nvm install stable
nvm use stable

#Install all the modules we desire
node_modules=&quot;mime qs hashlib connect ejs express hiredis policyfile redis uglify-js socket.io-client socket.io multi-node generic-pool&quot;
for m in $node_modules;
  do npm install $m;
done;
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;Copy and paste this script into an installnode.sh file&lt;/li&gt;
&lt;li&gt;chmod a+x installnode.sh&lt;/li&gt;
&lt;li&gt;./installnode.sh&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Make sure to run the script in the directory where you want the node_modules to be installed. That&#39;s it! Happy node hacking.&lt;/p&gt;
&lt;p&gt;Also, this script is... destructive. If you don&#39;t want to download and rebuild node every time you might want to remove the `rm -rf ~/.nvm`.&lt;/p&gt;
</content:encoded><category>node</category></item>
<item><title>How to Recruit Great Engineering Talent</title><link>https://jdconley.com/blog/how-to-recruit-great-engineering-talent</link><guid isPermaLink="false">tag:blogger.com,1999:blog-1741199026308686058.post-8119001092534412284</guid><pubDate>Thu, 28 Jul 2011 21:54:00 GMT</pubDate><description>Raiders of the Last Nerd made the front page of Hacker News yesterday and went a bit viral around the geek ecosystem. For good reason. Fueled by accelerating technology…</description><content:encoded>&lt;p&gt;&lt;a href=&quot;http://www.betabeat.com/2011/07/27/tech-recruiters/&quot;&gt;Raiders of the Last Nerd&lt;/a&gt;&amp;#160;made the front page of Hacker News yesterday and went a bit viral around the geek ecosystem. For good reason. Fueled by accelerating technology innovation, VC money, and even sometimes profit,&amp;#160;the job market for experienced engineering talent has been heating up all over the place. In recent months I have received an email or phone call from at least one recruiter per day and I haven&#39;t even worked for Google or Facebook or one of those other Golden Names. Last month, out of sheer frustration with the lack of quality, I wrote an open letter to recruiters titled &lt;a href=&quot;https://jdconley.com/blog/dearest-recruiter&quot;&gt;Dearest Recruiter&lt;/a&gt;. I&#39;d like to expand on that a bit.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The recruiting industry is broken.&lt;/strong&gt;&amp;#160;I&#39;m not talking about in-company recruiters here, but those outside agencies like the one Mr. Carvajal runs. There is a horde of non-technical, outgoing, sales people trying to court highly analytical, mildly autistic, geeks. After fielding calls and emails from recruiters for the last 12 years I&#39;ve grown a pretty thick skin and have become very defensive.&amp;#160;When I speak to a recruiter I assume everything they say is an attempted manipulation. I know that both myself and the company for which they are recruiting are getting ripped off.&amp;#160;I will often just hang up on them. They remind me of the slime I had to talk to every night during dinner before the &lt;a href=&quot;https://www.donotcall.gov/&quot;&gt;Do Not Call Registry&lt;/a&gt;&amp;#160;stopped most cold call telemarketers in their tracks.&lt;/p&gt;
&lt;p&gt;But on the other side of the coin, many geeks don&#39;t know their value, or don&#39;t know how to assert it, and the recruiters take advantage of that. Let&#39;s say you are recruited through one of the bigger tech recruiting firms such as TEKSystems or RHI. While you&#39;re on contract they&#39;ll probably take at least a 50% cut. Expect it to be much more if you&#39;re inexperienced and don&#39;t negotiate.&lt;/p&gt;
&lt;p&gt;When I started out in the industry I was much less jaded. In 1999, after dropping out of my second semester of college, I was referred by a family friend and took my first programming job at a ski boat manufacturing company. School was way behind the curve on technology and utterly boring for me.&amp;#160;Like most geeks in my generation, I&#39;d been messing with computers since I was five years old and programming somewhere shortly thereafter (it&#39;s a fuzzy memory now). I grew up in a small agricultural town and had no idea what wages should be or how to find out. This job paid a whopping $8/hr when minimum wage was $4.25. By 2001 I was making a stellar $13/hr. My friends though I was rich as I was living above the poverty line. But I got bored at that job so I found this cool web site called Dice.com where I could post my resume. This was my first experience with recruiters.&lt;/p&gt;
&lt;p&gt;They were all very nice people, these recruiters. They saw some fresh meat in me. A sucker. They pitched me to their client as this awesome young rock star. I was paid $35/hr (~$70k/yr). I later found out the company was billed more than 2x that amount. Was I really worth more than double that? And why didn&#39;t they tell me? My next position was also through a (different) contracting company. I was paid $45/hr (~$90k/yr) having 3 years of professional experience. I found out well after the fact that they billed about $100/hr.&amp;#160;That really got me thinking about recruiters.&lt;/p&gt;
&lt;p&gt;If you&#39;re a company and have a contractual relationship with a recruiting firm for direct hires, they&#39;ll probably take something like a 25% cut of the first year&#39;s salary of whoever they refer to your company. Of course it&#39;s in the contract. We had one of these at Hive7. On top of that, as a manager, I&#39;ve only had mild success with talent acquired through recruiting firms. The best hires I&#39;ve made have always been through my own network via referrals. Ouch!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Transparency is recommended.&lt;/strong&gt;&amp;#160;Us geeks are information and knowledge addicts. We learn and digest everything we possibly can. We embrace transparency. Just witness the popularity of the Open Source Software movement and how much value we place on being a part of it.&lt;/p&gt;
&lt;p&gt;Look. We know how the recruiting industry works. This antiquated people-trade reminds me of another slimy role that is currently being blown to pieces. If you tried to buy a new car 10 years ago you&#39;d have to go to a dealership, haggle with someone, get ripped off anyway, and walk away feeling dirty. Nowadays when I buy a car I do so online. I send emails to as many dealerships as I would drive to and ask for quotes. They provide quotes, and many provide a copy of the actual invoice they received when purchasing the car from the manufacturer. Of course they also receive some kick backs on the back end for volume and other special programs, but you can still walk away feeling like you weren&#39;t completely ripped off. The salesperson makes a hundred bucks for a few minutes work and you get a car.&lt;/p&gt;
&lt;p&gt;I&#39;m sure we&#39;ll see this level of transparency and marginalization of recruiters in the next 10 years. Just like the car salesman, technical recruiters are becoming largely irrelevant. Online social tools like Facebook, LinkedIn, Twitter, Google+ are expanding the available talent network one has access to. Up-and-coming geek-oriented job sites like &lt;a href=&quot;http://careers.stackoverflow.com/&quot;&gt;Stack Overflow Careers&lt;/a&gt;&amp;#160;are putting the tools into the hands of the hiring manager or HR department. All that&#39;s missing is a good aggregator of all these that can send me positions that would actually be interesting to me.&lt;/p&gt;
&lt;p&gt;I don&#39;t know much about the tech scene in NYC, but I have been contacted by recruiters there. They haven&#39;t had any more to offer than people over here in the San Francisco bay area. They&#39;re all the same slimy salespeople trying to convince you of their golden opportunity. I was going to use a used car salesman analogy here again, but I think something more fitting would be Viagra spammers. It is apparent that recruiters blindly send emails to hundreds of people hoping there will be some sort of a response.&lt;/p&gt;
&lt;p&gt;Most of the job reqs that come my way via recruiters are for Developer Lead or Senior Engineer type positions. Salaries are usually in the $100k-$150k range. There is the occasional Director level position, but salaries are roughly the same. After reading an article like Raiders of the Last Nerd, you&#39;d think that we were back in the .com boom with companies throwing sports cars and huge signing bonuses around. But that&#39;s just not true. The cases are much more isolated.&lt;/p&gt;
&lt;p&gt;In the interview Dave Carvajal stated that “We came from a place over the last two years where people were going to start-ups for below market [rates], People aren’t necessarily going to do that now.” This is partly true. But it really depends. It shows some of the lack-of-understanding of how the geek mind works. Maybe in the financial sector it&#39;s all about the money, but to a great hacker it&#39;s more about the project.&lt;/p&gt;
&lt;p&gt;The best engineers out there&amp;#160;&lt;strong&gt;do not work for the money&lt;/strong&gt; . Sure, they&#39;ll calculate how much their upside is at various acquisition prices, but they don&#39;t really care. Things like solving interesting problems, using new technology, making a visible impact, and working with a fun team are much more compelling for those that would work for a startup.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;For startups it&#39;s about the equity.&lt;/strong&gt; We&#39;re in the middle of a startup boom. Services like&amp;#160;&lt;a href=&quot;http://angel.co/&quot;&gt;AngelList&lt;/a&gt;&amp;#160;are making capital more easily accessible to good entrepreneurs, and incubators like&amp;#160;&lt;a href=&quot;http://ycombinator.com/&quot;&gt;YCombinator&lt;/a&gt;&amp;#160;are teaching young entrepreneurs the ropes. These startups are willing to offer large amounts of equity to early employees in exchange for sub-market pay rates. Any decent founder out there deeply believes her company is going to succeed and thus believes her equity is worth significantly more than any amount of cash. That, and, they don&#39;t have much cash to throw around. &amp;#160;There are a lot of very small funding rounds of &amp;lt; $1MM happening. That doesn&#39;t give a company without significant revenue much buying power if they want that to last a year.&lt;/p&gt;
&lt;p&gt;Do you want to be successful in recruiting someone? Try this on for size.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Show me MY money.&lt;/strong&gt;  On first contact, tell me how much money I will make. The exact dollar figure. If &amp;#160;you would be willing to pay $300k/yr for a role for the right person, just put that amount in the job. Us engineers know that there is a &lt;a href=&quot;http://haacked.com/archive/2007/06/25/understanding-productivity-differences-between-developers.aspx&quot;&gt;very high variance&lt;/a&gt; between the least productive and most productive members of our kind. Why not try paying for that?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tell me about the project.&lt;/strong&gt;&amp;#160;The project is just as important as the cash, if not more so. Tell me what it is. Don&#39;t tell me in weird abstract terms you don&#39;t understand. If you can&#39;t tell me what it is, don&#39;t bother talking to me.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Show me YOUR money.&lt;/strong&gt;  As a recruiter, how much money are you going to make on the deal? In our heads we&#39;re already doing the math and assume you&#39;re ripping us off. You might as well tell us, and break it down by the hour.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Don&#39;t ask how much I make.&lt;/strong&gt; We know that asking how much a person makes right now is really just gathering negotiation leverage. It&#39;s also wasting our time. You&#39;ll take that, then go back to the company, then get a new number, and blah blah blah.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tell me the company you&#39;re recruiting for.&lt;/strong&gt; The abstract job req is useless. Just say the name of the company. I will want to research them. It&#39;s more about the company fit than the particular job they&#39;re hiring for. Almost never do people do the same thing they were hired for in a company.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Let me talk.&lt;/strong&gt;&amp;#160;Many recruiters all-too-often steam roll conversations. This is super annoying. That&#39;s not how you sell.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Don&#39;t call me.&lt;/strong&gt; Oh yeah, and avoid calling me at all costs. Email or LinkedIn or text or something is much preferred. Phones are horrible. I hate talking on them. I&#39;m not alone.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Don&#39;t pretend you are technical.&lt;/strong&gt;&amp;#160;You bring up some recent tech news or talk about how you used to make web sites for fun or how awesome &quot;that C language&quot; is. We know you are just manipulating us to try to get us to open up to you. Give it up. Admit you&#39;re just a Pimp trying to pick up a new Ho.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Have something compelling.&lt;/strong&gt; When you&#39;re recruiting experienced talent out of a comfortable position you had better have something great. Either that&#39;s a truckload of cash (think multipliers on current salary), a first-employee position, a responsibility level-up, or a really freaking cool project. A combination of this stuff is preferred. Mention it upfront and don&#39;t dance around the important facts. We do not want to interview without knowing this stuff.&lt;/p&gt;
&lt;p&gt;It&#39;s a strange world we are living in right now. Jobless rates are insanely high, and here I am complaining about too many people wanting me to interview for jobs. It makes me feel extremely lucky to be in this industry.&lt;/p&gt;
</content:encoded></item>
<item><title>Dearest Recruiter</title><link>https://jdconley.com/blog/dearest-recruiter</link><guid isPermaLink="false">tag:blogger.com,1999:blog-1741199026308686058.post-4712520386674400450</guid><pubDate>Mon, 27 Jun 2011 21:27:00 GMT</pubDate><description>Update:I expanded on this a bit over here: http://blog.jdconley.com/2011/07/how-to-recruit-great-engineering-talent.html I&#39;m taking some time out of my lunch break today, when…</description><content:encoded>&lt;p&gt;&lt;em&gt;Update:&lt;/em&gt; I expanded on this a bit over here: &lt;a href=&quot;https://jdconley.com/blog/how-to-recruit-great-engineering-talent&quot;&gt;http://blog.jdconley.com/2011/07/how-to-recruit-great-engineering-talent.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I&#39;m taking some time out of my lunch break today, when I&#39;d much rather be indulging in some geek porn over at &lt;a href=&quot;http://news.ycombinator.com/&quot;&gt;Hacker News&lt;/a&gt;, to submit a plea on behalf of all the in-demand geeks out there.&lt;/p&gt;
&lt;p&gt;You probably found my resume, my consulting company, my blog, my Linked In, my Facebook profile, the MySpace profile I haven&#39;t taken the time to delete, my Stack Exchange profile, and some personal blogs about my kids via Google. Did you actually read any of it? No? I am an entrepreneurial generalist that prefers to balance business, product, and technology. I do not want a heads-down, order-following, engineering role.&lt;/p&gt;
&lt;p&gt;Yes, I joke about golden handcuffs, but I am happy in my current position. I work from home for the most part. I am working on autonomous startup-like projects that provide great satisfaction. I have some cool benefits and awesome perks. Oh yeah, and I&#39;m paid well.&lt;/p&gt;
&lt;p&gt;But, I digress. I do enjoy money. I am human, and a good American consumer. I like to buy stuff. My wife likes to buy stuff. We like vacationing. It&#39;s fun. So I&#39;ll make you an offer. I will consider your position if you can provide compensation like &lt;a href=&quot;http://adtmag.com/Articles/2011/05/27/What-Highest-Paid-Programmers-Earn.aspx?Page=2&quot;&gt;Sergey Aleynikov&lt;/a&gt;. Let&#39;s round it up to $500k/yr total compensation, and the work better be self rewarding as well. Yes, I&#39;m serious.&lt;/p&gt;
&lt;p&gt;Do I feel bad for asking for such a huge sum? No, I don&#39;t. Am I entitled to it? Probably not. But I&#39;m happy in my position and a few thousand dollars extra will not change my mind. I am not interested in a market-competitive salary. I am not interested in being the 25th employee at the next great Groupon clone. I understand how company capitalization and ESOP&#39;s work.&lt;/p&gt;
&lt;p&gt;Now, I might be interested in being the first employee at a startup or a technical cofounder, but it had better be really darn interesting. I&#39;ve got my own ideas and stack of half finished prototypes to productize. :) On that note, consulting arrangements at &amp;gt; $200/hr will also be considered.&lt;/p&gt;
&lt;p&gt;Stop contacting me with inappropriate jobs that have nothing to do with my experience. Stop attempting to relocate me to Indiana. Stop asking what it would take for me to move to a new position. Stop wasting my time. Please. Stop.&lt;/p&gt;
&lt;p&gt;Best Regards,&lt;/p&gt;
&lt;p&gt;The In-Demand Geek&lt;/p&gt;
</content:encoded><category>business</category><category>random</category></item>
<item><title>ValidateInput Attribute Doesn&#39;t Work in ASP.NET 4.0</title><link>https://jdconley.com/blog/validateinput-attribute-doesnt-work-in</link><guid isPermaLink="false">tag:blogger.com,1999:blog-1741199026308686058.post-7924513367780140302</guid><pubDate>Mon, 19 Apr 2010 20:28:00 GMT</pubDate><description>Today I decided to upgrade some of our new projects (top secret, shhh) to Visual Studio 2010, ASP.NET 4.0, and ASP.NET MVC 2.0. There are about a million new features that look…</description><content:encoded>&lt;p&gt;Today I decided to upgrade some of our new projects (top secret, shhh) to &lt;a href=&quot;http://weblogs.asp.net/scottgu/archive/2010/04/12/visual-studio-2010-and-net-4-released.aspx&quot;&gt;Visual Studio 2010&lt;/a&gt;, ASP.NET 4.0, and &lt;a href=&quot;http://weblogs.asp.net/scottgu/archive/2010/03/11/asp-net-mvc-2-released.aspx&quot;&gt;ASP.NET MVC 2.0&lt;/a&gt;. There are about a million new features that look quite useful in all of these new releases. We have some fairly complex projects so I was excepting a few speed bumps, but, not this one.&lt;/p&gt;
&lt;p&gt;It seems with every new release Microsoft adds annoying (isn&#39;t security always?) features to protect us from ourselves. Way back when they added the idea of &lt;a href=&quot;http://www.asp.net/learn/whitepapers/request-validation/&quot;&gt;Request Validation&lt;/a&gt;. If ASP.NET thinks a user is posting something &quot;bad&quot; to the server (i.e. things that lead to XSS attacks), the request is denied. This is cool except when you want to, say, allow the user to input HTML or have a web service that takes XML as a parameter in a form, or use a &quot;:&quot; in your URL. In ASP.NET web forms you work around this feature by turning it off at the page level or globally in your web.config through the validateRequest option. In MVC you use the ValidateInput attribute on your action.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;This is really really important:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In .NET 2.0-3.5 the runtime only validated requests sent to .aspx pages, but &lt;a href=&quot;http://www.asp.net/learn/whitepapers/aspnet4/breaking-changes/#0.1__Toc256770147&quot;&gt;that has now changed&lt;/a&gt; and &lt;strong&gt;any&lt;/strong&gt; request will be validated, even it is sent to a custom handler, or an MVC application.&lt;/p&gt;
&lt;p&gt;ASP.NET MVC implements its own request validation, which is also on by default. To turn it off you simply slap a ValidateInput(false) attribute on your controller action. This is fine and dandy, except with the latest ASP.NET 4.0 changes, &lt;a href=&quot;http://connectppe.microsoft.com/VisualStudio/feedback/details/543069/validateinput-false-not-working&quot;&gt;it no longer works&lt;/a&gt; and an exception is thrown. So you might see an error like:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A potentially dangerous Request.Form value was detected from the client&lt;/strong&gt;  or &lt;strong&gt;A potentially dangerous Request.Path value was detected from the client&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The workaround is pretty easy. Just follow the instructions on the &lt;a href=&quot;http://www.asp.net/learn/whitepapers/aspnet4/breaking-changes/#0.1__Toc256770147&quot;&gt;ASP.NET 4.0 Breaking Changes&lt;/a&gt; page. Stick this XML in your web.config to revert to the behavior as it were in ASP.NET 2.0-3.5. This will put request validation back in the hands of the ASP.NET MVC engine and your ValidateInput attribute will start working again.&lt;/p&gt;
</content:encoded><category>.net</category><category>asp.net</category></item>
<item><title>Mr. Sprite Sheet, Meet Ms. MovieClip</title><link>https://jdconley.com/blog/mr-sprite-sheet-meet-ms-movieclip</link><guid isPermaLink="false">tag:blogger.com,1999:blog-1741199026308686058.post-6147256010649956063</guid><pubDate>Wed, 10 Mar 2010 00:18:00 GMT</pubDate><description>In Youtopia we wanted to have animations. We also wanted to have thousands of buildings on the screen at once. Anyone who has done a lot of Flash development will tell you that…</description><content:encoded>&lt;p&gt;In &lt;a href=&quot;http://pushbuttonengine.com/devgallery/youtopia&quot;&gt;Youtopia&lt;/a&gt; we wanted to have animations. We also wanted to have thousands of buildings on the screen at once. Anyone who has done a lot of Flash development will tell you that these two things are not compatible. You simply cannot create that many movie clip instances and have them playing. But, all is not lost! With a sprite sheet animation system like the one in &lt;a href=&quot;http://pushbuttonengine.com/&quot;&gt;PushButton Engine&lt;/a&gt; (PBE) you can have your cake and eat it too!&lt;/p&gt;
&lt;p&gt;Sprite sheets are as old as video games that have pre-rendered art. The basic idea is you draw a bunch of frames of an animation (or multiple animations) and put them on a single image. You can see some examples &lt;a href=&quot;http://www.mariomayhem.com/downloads/sprites/super_mario_bros_sprites.php&quot;&gt;online&lt;/a&gt;. The software knows how to read and draw a frame of the desired animation from that one big graphic, and that&#39;s what you see on the screen. Easy!&lt;/p&gt;
&lt;p&gt;However, sprite sheets also have their down sides. First, they aren&#39;t made to scale. We&#39;re talking bitmap graphics here. Your resized image is only going to look as good as your resizing code can make it look (which usually is not very good). Second, animations with a lot of frames can create very large file sizes. A five second animation at 30 frames per second means you end up with all 150 frames of the animation on a single image.&lt;/p&gt;
&lt;p&gt;This is where movie clips come in. &quot;But wait,&quot; you say with bewilderment, &quot;didn&#39;t you tell me earlier we couldn&#39;t use movie clips.&quot; Why yes I did, so let me explain. Flash was designed from its inception to create small file sizes for downloads. It was also designed to support resizing. This is done using &lt;a href=&quot;http://en.wikipedia.org/wiki/Vector_graphics&quot;&gt;vector graphics&lt;/a&gt; which can be animated in a movie clip. We should take advantage of this feature.&lt;/p&gt;
&lt;p&gt;One of the bits of code I contributed to PBE was the SWFSpriteSheetComponent. It takes an instance of a MovieClip and converts each frame into a bitmap. It then exposes these bitmaps to the PBE rendering engine as if they were part of a sprite sheet. Viola! You get the best of both worlds. A small download size, the option to render your animation at any scale, and super awesome performance. Using this technique and well drawn vector graphics we were able to save over 5X on the download size of Youtopia as compared to sprite sheets and get the same performance!&lt;/p&gt;
&lt;p&gt;NOTE: If you&#39;re not familiar with PBE you might want to skim through &lt;a href=&quot;http://pushbuttonengine.com/docs/&quot;&gt;the docs&lt;/a&gt; before diving into my code below. I&#39;d highly recommend the video talks. The composite entity architecture can throw you for a loop if you&#39;re not used to seeing it.&lt;/p&gt;
&lt;p&gt;Using the SWFSpriteSheetComponent is really easy and I&#39;ve created an example application to show it off. The application spawns a sleeping &lt;a href=&quot;http://coderhump.com/&quot;&gt;Ben Garney&lt;/a&gt; every second and makes him move. There are some animated zzz&#39;s to indicate that, regardless of the smile, he is in fact sleeping. Ben is the lead developer on PBE, so he&#39;s getting picked on. ;) &lt;a href=&quot;http://jdconley.com/garney/&quot;&gt;Click here&lt;/a&gt; to see the app. You can also &lt;a href=&quot;https://docs.google.com/viewer?a=v&amp;pid=explorer&amp;chrome=true&amp;srcid=0B7Ew2HKAAmajNTI5NDBiMjktOWFlMC00M2JiLTk0ZWUtNmY0MGVmNzc3MzUx&amp;hl=en_US&quot;&gt;download the source&lt;/a&gt; and follow along at home.&lt;/p&gt;
&lt;p&gt;The process starts by creating and exporting a MovieClip in your fla with a flash.display.MovieClip base class. Give it a class name that you&#39;re not going to forget. In this example we call it &quot;z_fx&quot;. Then publish the swf and put it somewhere that your PBE application can find it. The example has a &quot;res&quot; folder where I put the effects.swf. The CS3 format effects.fla (created for me by Jesse Tudela here at Hive7) is in the res folder in the &lt;a href=&quot;https://docs.google.com/viewer?a=v&amp;pid=explorer&amp;chrome=true&amp;srcid=0B7Ew2HKAAmajNTI5NDBiMjktOWFlMC00M2JiLTk0ZWUtNmY0MGVmNzc3MzUx&amp;hl=en_US&quot;&gt;download&lt;/a&gt; if you want to check it out. Now on to the code!&lt;/p&gt;
&lt;p&gt;For easy deployment we embed the effects.swf and the garney.png file using PBE&#39;s ResourceBundle like so:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package{   import com.pblabs.engine.resource.ResourceBundle;   public class Resources extends ResourceBundle   {       public static const EFFECTS_PATH:String = &quot;../res/effects.swf&quot;;       public static const GARNEY_PATH:String = &quot;../res/garney.png&quot;;             [Embed(source=&quot;../res/effects.swf&quot;,mimeType=&#39;application/octet-stream&#39;)]       public var effects:Class;       [Embed(source=&quot;../res/garney.png&quot;,mimeType=&#39;application/octet-stream&#39;)]       public var garney:Class;   }}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now on to our &quot;main&quot; method. We start off by creating a SceneView, which is the target where PBE will draw stuff. Then we call startup, load our embedded resources, and create the scene. This is all standard PBE initialization. A ThinkingComponent is added to the scene entity in order to spawn Garney instances based on the game&#39;s virtual time. And finally, we register our garney entity factory with the TemplateManager and spawn a Garney!&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// The SceneView is where PBE will draw tovar sv:SceneView = new SceneView();addChild(sv);// Start the logger, processmanager, etcPBE.startup(this);// Embed my resourcesPBE.addResources(new Resources());// Create a basic scene through codevar scene:IEntity = PBE.initializeScene(sv);// ThinkingComponent is an efficient Timer based on virtualTime rather than real timescene.addComponent(new ThinkingComponent(), &quot;spawnThinker&quot;);// Register the callback for my &quot;garney&quot; template that will be used to instantiate garneyssetupTemplate();// Spawn a garney then kick off the timer. They keep coming, eeek!spawn();
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The setupTemplate method is where all the interesting stuff happens. In here we choose all the components that make up our entity and determine how they relate to each other.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;private function setupTemplate():void{   PBE.templateManager.registerEntityCallback(&quot;garney&quot;,       function():IEntity       {           var e:IEntity = PBE.allocateEntity();                     // Spatial component knows where to put the garney           var spatial:SimpleSpatialComponent = new SimpleSpatialComponent();           spatial.spatialManager = PBE.spatialManager;                     // Rendering component knows how to draw the garney           var render:SpriteRenderer = new SpriteRenderer();           render.fileName = Resources.GARNEY_PATH;           render.positionProperty = new PropertyReference(&quot;@spatial.position&quot;);           render.scene = PBE.scene;                     // Here&#39;s the SWFSpriteSheet magic!           var fxSheet:SWFSpriteSheetComponent = new SWFSpriteSheetComponent();           fxSheet.swf = PBE.resourceManager.load(Resources.EFFECTS_PATH, SWFResource) as SWFResource;           fxSheet.clipName = &quot;z_fx&quot;;                     // Fx Rendering component knows how to draw the z&#39;s from the spritesheet           var fxRender:SpriteSheetRenderer = new SpriteSheetRenderer();           fxRender.positionProperty = new PropertyReference(&quot;@spatial.position&quot;);           fxRender.positionOffset = new Point(30, 10);           fxRender.scene = PBE.scene;                     // Need an animation controller to assign and animate the sprite sheet on the renderer           var animator:AnimationController = new AnimationController();           animator.spriteSheetReference = new PropertyReference(&quot;@fxRender.spriteSheet&quot;);           animator.currentFrameReference = new PropertyReference(&quot;@fxRender.spriteIndex&quot;);           var idle:AnimationControllerInfo = new AnimationControllerInfo();           idle.loop = true;           idle.spriteSheet = fxSheet;           idle.frameRate = 30; // In PBE your animation framerate can be independent of your stage framerate           animator.animations[&quot;idle&quot;] = idle;           animator.defaultAnimation = &quot;idle&quot;;                     // Garneys self destruct after a random amount of time           var suicide:ThinkingComponent = new ThinkingComponent();                     // Add all the components to the entity           e.addComponent(spatial, &quot;spatial&quot;);           e.addComponent(render, &quot;render&quot;);           e.addComponent(fxSheet, &quot;fxSheet&quot;);           e.addComponent(fxRender, &quot;fxRender&quot;);           e.addComponent(animator, &quot;animator&quot;);           e.addComponent(suicide, &quot;suicide&quot;);                     e.initialize();           return e;       });}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &quot;garney&quot; template is made up of six distinct components. Each of these components perfmorm a small piece of highly specialized work. I created two components for rendering, one for the garney sprite and one for the animated z&#39;s. The z&#39;s use a SpriteSheetRenderer and a SWFSpriteSheetComponent. Both renderers are positioned based on the position property on the spatial component. The AnimationController is a very powerful class that lets you do things like automatically change out the animation being rendered based on an event firing. But, that&#39;s probably a post for another day. In this case it just plays the z&#39;s animation on the fxRender component.&lt;/p&gt;
&lt;p&gt;All of this gets tied together in the spawn method, which creates a new garney entity based on the template, assigns it some random values for position and velocity, makes sure it draws the most recently spawned entity on top, picks a random time for the entity to commit suicide, and schedules the next spawn.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;private function spawn():void{   // Create a garney!   var garney:IEntity = PBE.templateManager.instantiateEntity(&quot;garney&quot;);     // Randomly position a garney!   var spatial:SimpleSpatialComponent = garney.lookupComponentByName(&quot;spatial&quot;) as SimpleSpatialComponent;   spatial.position = new Point(Math.random() * 800, Math.random() * 600);   spatial.velocity =  new Point(Math.random() * 50 * (Math.random() &amp;lt; .5 ? -1 : 1), Math.random() * 50 * (Math.random() &amp;lt; .5 ? -1 : 1));     // Choose when this garney commits suicide, up to 20,000 virtual MS from now   var suicide:ThinkingComponent = garney.lookupComponentByName(&quot;suicide&quot;) as ThinkingComponent;   suicide.think(garney.destroy, Math.random() * 20000);     // Set the zIndex so our components render consistently in spawn-order   var render:DisplayObjectRenderer = garney.lookupComponentByName(&quot;render&quot;) as DisplayObjectRenderer;   render.zIndex =   _zIndex;     var fxRender:DisplayObjectRenderer = garney.lookupComponentByName(&quot;fxRender&quot;) as DisplayObjectRenderer;   fxRender.zIndex =   _zIndex;     // Grab the global spawn thinking component and schedule a think   var thinker:ThinkingComponent = PBE.lookupComponentByName(&quot;SceneDB&quot;, &quot;spawnThinker&quot;) as ThinkingComponent;   thinker.think(spawn, 1000);}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That&#39;s all there is to it! There are some caveats, though. Make sure you keep your source MovieClips really simple. Just like it is CPU intensive to play a complex MovieClip, it is CPU intensive to render each frame to a bitmap. In addition, nested clips with separate timelines and as3 code in the clip that is not based on the timeline will not be executed. This works really well for simple frame based animations, but is not designed for complex interactive clips with tweening. YMMV.&lt;/p&gt;
&lt;p&gt;Let me know if you have any questions or if you&#39;re interested in any other PBE related topics. Also, PBE 1.0 is out! Download it from the &lt;a href=&quot;http://pushbuttonengine.com/download/&quot;&gt;project site&lt;/a&gt;. This example includes the 1.0 release swc.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.google.com/viewer?a=v&amp;pid=explorer&amp;chrome=true&amp;srcid=0B7Ew2HKAAmajNTI5NDBiMjktOWFlMC00M2JiLTk0ZWUtNmY0MGVmNzc3MzUx&amp;hl=en_US&quot;&gt;Download the source code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://jdconley.com/garney/&quot;&gt;See the demo&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>as3</category><category>tuning</category></item>
<item><title>Angry Players Make Sunday More Interesting</title><link>https://jdconley.com/blog/angry-players-make-sunday-more</link><guid isPermaLink="false">tag:blogger.com,1999:blog-1741199026308686058.post-3298497982786863353</guid><pubDate>Sun, 22 Nov 2009 23:48:00 GMT</pubDate><description>Youtopia has been growing quickly the last couple of weeks. It&#39;s fun to watch and the team is really excited about it. Of course, with the growth comes a lot of performance…</description><content:encoded>&lt;p&gt;Youtopia has been growing quickly the last couple of weeks. It&#39;s fun to watch and the team is really excited about it. Of course, with the growth comes a lot of performance tuning with our code. Today we hit an issue I wasn&#39;t expecting at all. . .&lt;/p&gt;
&lt;p&gt;We&#39;ve been running Windows 2008, IIS7, and ASP.NET 3.5 in production for a while now, but haven&#39;t had to do much of any performance tuning. It &lt;em&gt;just works&lt;/em&gt; , and is fast. Which is awesome!&lt;/p&gt;
&lt;p&gt;But today, Youtopia was running slowly and requests were hanging so I investigated. The databases were performing normally and not having any locking issues. The network looked good. The memcached cluster was healthy. The queueing service looked great. The ASP.NET performance counters even looked good at first glance.&lt;/p&gt;
&lt;p&gt;None of the diagnostic performance monitors I&#39;d used in the past (such as Requests in Application Queue) showed the issue, but requests were absolutely being queued -- or otherwise not processed immediately. There were also plenty of free worker and IOCP threads. The only thing that clued me in was the Pipeline Instance Count and Requests Executing counters were exactly the same (96) on all the servers. So I started investigating from there.&lt;/p&gt;
&lt;p&gt;It turns out that &lt;a href=&quot;http://blogs.msdn.com/tmarq/archive/2007/07/21/asp-net-thread-usage-on-iis-7-0-and-6-0.aspx&quot;&gt;due to the way IIS7 ASP.NET integrated mode threading model&lt;/a&gt; functions there is a (configurable) request limit of 12 per CPU. We hit this limit in Youtopia today because we hold open requests for asynchronous Comet-like communications and there were over 288 people online simultaneously. Our three eight core web servers each had 96 (8*12) people connected to them and weren&#39;t really serving any other requests. We aren&#39;t running into any thread configuration limits as the long running requests are asynchronous and not using ASP.NET worker threads.&lt;/p&gt;
&lt;p&gt;Here are a few great links that came out of my research.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://blogs.msdn.com/tmarq/archive/2007/07/21/asp-net-thread-usage-on-iis-7-0-and-6-0.aspx&quot;&gt;http://blogs.msdn.com/tmarq/archive/2007/07/21/asp-net-thread-usage-on-iis-7-0-and-6-0.aspx&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://support.microsoft.com/kb/816995&quot;&gt;http://support.microsoft.com/kb/816995&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://msdn.microsoft.com/en-us/library/ee377050%28BTS.10%29.aspx&quot;&gt;http://msdn.microsoft.com/en-us/library/ee377050(BTS.10).aspx&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://blogs.msdn.com/webtopics/archive/2009/02/13/asp-net-hang-in-iis-7-0.aspx&quot;&gt;http://blogs.msdn.com/webtopics/archive/2009/02/13/asp-net-hang-in-iis-7-0.aspx&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With ASP.NET 3.5 SP1 it boils down to a simple configuration file change. Use something like this in the aspnet.config file (in x64 it&#39;s at C:\Windows\Microsoft.NET\Framework64\v2.0.50727\aspnet.config). This is the default. Adjust maxConcurrentRequestsPerCPU to suit your needs.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;system.web&amp;gt;   &amp;lt;applicationPool maxConcurrentRequestsPerCPU=&quot;12&quot; maxConcurrentThreadsPerCPU=&quot;0&quot; requestQueueLimit=&quot;5000&quot;/&amp;gt;&amp;lt;/system.web&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In addition, the application pool needs to be configured to allow more requests. By default it only allows 1000 concurrent requests. This is done under the Advanced Settings for the application pool in the IIS 7 manager. Set Queue Length to 5000 to match this system level configuration.&lt;/p&gt;
</content:encoded><category>asp.net</category><category>tuning</category></item>
<item><title>Ditch Your Events (Part 1)</title><link>https://jdconley.com/blog/ditch-your-events-part-1</link><guid isPermaLink="false">tag:blogger.com,1999:blog-1741199026308686058.post-7793214738393095802</guid><pubDate>Mon, 16 Nov 2009 19:30:00 GMT</pubDate><description>About four months ago Max, Hive7&#39;s Lawful Evil CEO, decided we needed to take our games to the next level and build something fun and accessible that everyone who plays &quot;those…</description><content:encoded>&lt;p&gt;About four months ago Max, Hive7&#39;s &lt;a href=&quot;http://corp.hive7.com/about/&quot;&gt;Lawful Evil CEO&lt;/a&gt;, decided we needed to take our games to the next level and build something fun and accessible that everyone who plays &quot;those farming games&quot; would want to play. We all brainstormed, pitched our ideas to the company, and everyone voted by comparing every idea against every other – I wish we had a digital photo of the giant matrix on the whiteboard. There were a bunch of great ideas, but in the end... I won! &lt;a href=&quot;http://apps.facebook.com/you-topia/landing?ref=jd&quot;&gt;Youtopia&lt;/a&gt; was born.&lt;/p&gt;
&lt;p&gt;Youtopia was released to the public about three months from its inception. Hats off to the dev and art team for pulling this one together. A new technology for the developers and fully animated objects for the art team led to much blood, sweat, and tears, but we got &#39;er done! Of course, we&#39;re still actively developing Youtopia, and there are lots of great things planned for the future! But, back to my tech article...&lt;/p&gt;
&lt;p&gt;It&#39;s been a long time since I&#39;ve stepped out of my comfort zone and learned a new (to me) technology. Don&#39;t get me wrong, I&#39;m always experimenting with the lastest .NET based thingie-ma-bobbers out there, but I haven&#39;t used a completely foreign development environment since C#/.NET came out over eight years ago. But for this project I needed to learn Flash/AS3, and it needed to be done yesterday. Luckily for me nobody else on our dev team knew Flash so I could still pretend like I knew what I was talking about and make lots of (un)educated architectural decisions without anyone being the wiser!&lt;/p&gt;
&lt;p&gt;One such recent decision was to use an event driven property binding system. Youtopia&#39;s engine is based on a great open source game engine, brought to you from some of the Dyamix/GarageGames people, called the &lt;a href=&quot;http://www.pushbuttonengine.com/&quot;&gt;PushButton Engine&lt;/a&gt; (or PBE). In PBE there is a class called PropertyReference. This class facilitates a late-bound approach for one component to read the value of a property (member variable or getter/setter) on another component. It&#39;s a pretty cool pattern, but requires you to poll the target component whenever you want to know if the property changed. This works fine when you&#39;re talking about 10&#39;s or 100&#39;s of components. But in Youtopia we have thousands of entities in the scene at once. We needed this binding to be event-driven.&lt;/p&gt;
&lt;p&gt;Of course, with my .NET background I immediately reached for the &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged.aspx&quot;&gt;INotifyPropertyChanged&lt;/a&gt; pattern used in .NET&#39;s data binding infrastructure. With INotifyPropertyChanged it is the responsibility of the object owning the property to raise an event whenever a property value changes. Any listeners will then immediately know they need to poll for the new value if they want it.&lt;/p&gt;
&lt;p&gt;This works great in .NET and is very performant. But in Flash, events are a whole other story. They are an extremely feature-rich subsystem that I don&#39;t really want to get into. In the end, all the features and memory allocations when you raise an event lead to poorer performance than we needed for Youtopia. We need every bit of CPU power on that single Flash thread and really shouldn&#39;t be wasting it raising events.&lt;/p&gt;
&lt;p&gt;So, I shamelessly copied the .NET patterns and brought them over to AS3. Let&#39;s start at the core. In order for things to perform their best, I &lt;a href=&quot;http://troygilbert.com/2009/09/events-vs-callbacks/&quot;&gt;couldn&#39;t use&lt;/a&gt; the built-in Events. Though Troy did the benchmarking legwork, he didn&#39;t provide an implementation we could use to register callbacks and call multiple functions. So, I wrote a MulticastFunction that behaves a whole lot like the &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/system.multicastdelegate.aspx&quot;&gt;MulticastDelegate&lt;/a&gt; in .NET. Usage is really straightforward.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var func:MulticastFunction = new MulticastFunction();//register my listener callbackfunc.add(  function():void   {    //this callback does amazingly cool stuff    trace(&quot;hello from the callback&quot;);  });//calls all the callbacks that have been added, in the order they were addedfunc.apply();
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see, dealing with the MulticastFunction is a lot like the EventDispatcher, but each MulticastFunction is only designed to be used for a single event. So, to use it for events, create a public getter on your class named something reasonable and add your callbacks to it. Done!&lt;/p&gt;
&lt;p&gt;Ok, I realize I keep talking about event dispatching speed, but haven&#39;t put my money where my mouth is. I wrote some benchmarks of my own and here is the output with a release build, in the latest standalone Flash 10 player. It does five test runs. &lt;a href=&quot;https://docs.google.com/viewer?a=v&amp;pid=explorer&amp;chrome=true&amp;srcid=0B7Ew2HKAAmajMTM5NmIzMTUtYTJiNC00MTcxLWFhOGYtMjRmM2Q2ODA0YThh&amp;hl=en_US&quot;&gt;Download the Source&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;running tests...Event dispatching took 848msMulticastFunction took 355msrunning tests...Event dispatching took 846msMulticastFunction took 351msrunning tests...Event dispatching took 834msMulticastFunction took 352msrunning tests...Event dispatching took 836msMulticastFunction took 351msrunning tests...Event dispatching took 823msMulticastFunction took 343ms
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Yup, that&#39;s right. MulticastFunction is nearly 2.5x faster, and I haven&#39;t spent much time tuning it. For example, it&#39;s using an Array under the hood and doing more work than it needs to during the apply call. Events will also become less performant over time as you have to create (and potentially clone) Event objects for every dispatch, causing a lot of garbage collection pressure. Here&#39;s the MulticastFunction, with lots of comments or you can &lt;a href=&quot;https://docs.google.com/viewer?a=v&amp;pid=explorer&amp;chrome=true&amp;srcid=0B7Ew2HKAAmajMTM5NmIzMTUtYTJiNC00MTcxLWFhOGYtMjRmM2Q2ODA0YThh&amp;hl=en_US&quot;&gt;download the source&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package com.jdconley{    /**     * A wrapper that mimics the synchronous behavior of the MulticastDelegate used in .NET for events.     * This doesn&#39;t support any of the async methods, as we don&#39;t have free threading here.     * It also doesn&#39;t support return values.     * See: http://msdn.microsoft.com/en-us/library/system.multicastdelegate.aspx     */    public class MulticastFunction    {        private var _functions:Array = [];        private var _iterators:int = 0;        /**         * Adds a function to be called when apply is called.         * If the function is already in the list it won&#39;t be added twice.         * Returns true if the function was added.         **/        public function add(func:Function):Boolean        {            var i:int = _functions.indexOf(func);            if (i &amp;gt; -1)                return false;            //add new functions to the end so they are picked up live during an apply            _functions.push(func);            return true;        }        /**         * Removes a function to be called when apply is called.         * Returns true if the function was removed.         **/        public function remove(func:Function):Boolean        {            var i:int = _functions.indexOf(func);            if (i &amp;lt; 0)                return false;            if (_iterators == 0)                _functions.splice(i, 1);            else                _functions[i] = null;            return true;        }        /**         * Synchronously applies all functions that have been added.         * Functions can be safely added or removed during an apply and changes will take effect immediately.         * Added functions will be called, and removed functions will not.         **/        public function apply(thisArg:*=null, argArray:*=null):void        {            _iterators  ;            var holes:Boolean = false;                        for (var i:int = 0; i &amp;lt; _functions.length; i  )            {                var f:Function = _functions[i];                if (f == null)                    holes = true;                else                    f.apply(thisArg, argArray);            }            //cleanup holes left by removing functions during this apply call.            //if any of the function apply&#39;s throw an error the state of _iterators will be off.            //but, we&#39;ll only leak array slot memory if functions are removed.            //putting a try/finally or try/catch block here significantly decreases performance.            if (--_iterators == 0 &amp;amp;&amp;amp; holes)            {                for (i = _functions.length - 1; i &amp;gt;= 0; i--)                {                    if (_functions[i] == null)                        _functions.splice(i, 1);                }                        }        }        /**         * Removes all functions from the list. Stops the current apply call, if there is one.         **/        public function clear():void        {            _functions = [];        }    }}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Although capture, bubble, weak references, and priority are handy features of the Flash eventing system, they&#39;re not always necessary and will hurt your performance when you might have thousands of them firing per frame.&lt;/p&gt;
&lt;p&gt;In Part 2 we&#39;ll put this MulticastFunction to use in a more meaningful way with the INotifyPropertyChanged implementation.&lt;/p&gt;
</content:encoded><category>.net</category><category>as3</category><category>tuning</category></item>
<item><title>Anyone still out there?</title><link>https://jdconley.com/blog/anyone-still-out-there</link><guid isPermaLink="false">tag:blogger.com,1999:blog-1741199026308686058.post-3759175721413587676</guid><pubDate>Fri, 13 Nov 2009 22:49:00 GMT</pubDate><description>Wow, I haven&#39;t posted in a while. In recent months I&#39;ve been focused intently on a few things. Babies! My wife and I had twins in February. Learning a new technology while…</description><content:encoded>&lt;p&gt;Wow, I haven&#39;t posted in a while. In recent months I&#39;ve been focused intently on a few things.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Babies! My wife and I had twins in February.&lt;/li&gt;
&lt;li&gt;Learning a new technology while shipping an &lt;a href=&quot;http://apps.facebook.com/you-topia/landing?ref=jd&quot;&gt;amazing game&lt;/a&gt; at Hive7.&lt;/li&gt;
&lt;li&gt;Working on a &lt;a href=&quot;http://www.pushbuttonengine.com/&quot;&gt;cool open source project&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I won&#39;t bore all you geeks with the baby stuff. If you can find the link to my personal blog you can go look at lots of pictures.&lt;/p&gt;
&lt;p&gt;You should all check out &lt;a href=&quot;http://apps.facebook.com/you-topia/landing?ref=jd&quot;&gt;Youtopia&lt;/a&gt; (the new game we shipped). We&#39;re really proud of this one.&lt;/p&gt;
&lt;p&gt;So, drumroll please... *in my most awesome announcer voice* And, the new technology is... Flash! That&#39;s right, this Microsoft fanboy is now in the Flash camp. I really wish I could be working with Silverlight, but well, you can&#39;t build a game that runs on Facebook and make people install something. It just won&#39;t work. Once Silverlight has a market share more like Flash Player, then we&#39;re in business.&lt;/p&gt;
&lt;p&gt;What do I dislike most about Flash? The development environments (yes, plural) for Flash pale in comparison to Visual Studio. Compiling is slow. Stuff crashes a lot. Heck, I even got the compiler to throw a null pointer exception on a few occasions! Debugging is a pain. The garbage collector isn&#39;t very fast. You only have &lt;strong&gt;one&lt;/strong&gt; thread to work with. Hey Adobe is it still 1998?&lt;/p&gt;
&lt;p&gt;All that being said, Flash (and more specifically Actionscript 3 and Flash Player) is actually really mature now and a decent piece of technology. It has most things a developer looks for in a language/runtime. And, well, it allows us to create a really rich and interactive experience that runs in your browser and doesn&#39;t require you to install anything. Obviously the business case here wins out over my whining.&lt;/p&gt;
&lt;p&gt;I think I&#39;ve spent enough time talking. Coming very soon, a useful post that contains lots of great technical info from the perspective of a C# junky diving head first into Flash.&lt;/p&gt;
</content:encoded><category>.net</category><category>as3</category></item>
<item><title>Functional Optimistic Concurrency in C#</title><link>https://jdconley.com/blog/functional-optimistic-concurrency-in-c</link><guid isPermaLink="false">tag:blogger.com,1999:blog-1741199026308686058.post-148808662145526727</guid><pubDate>Fri, 26 Jun 2009 07:00:00 GMT</pubDate><description>A few months ago Phil Haack wrote about how C# 3.0 is a gateway drug to functional programming. (Yeah, that&#39;s how long ago I started writing this blog.) I couldn&#39;t agree more.…</description><content:encoded>&lt;p&gt;A few months ago Phil Haack wrote about how C# 3.0 is a &lt;a href=&quot;http://haacked.com/archive/2009/02/15/the-functional-language-gateway-drug.aspx&quot;&gt;gateway drug&lt;/a&gt; to functional programming. (Yeah, that&#39;s how long ago I started writing this blog.) I couldn&#39;t agree more. I find myself solving problems using functional rather than imperative programming quite often nowadays. It&#39;s much more elegant for many problem spaces.&lt;/p&gt;
&lt;p&gt;Before we go any further, here&#39;s the sample app used for this article. Even if you don&#39;t like my writing, you should play with it. Yeah, you! &lt;a href=&quot;https://docs.google.com/viewer?a=v&amp;pid=explorer&amp;chrome=true&amp;srcid=0B7Ew2HKAAmajMGNmZGNjNTMtYzQwMy00MWJkLTk3MDItODJhYzJjOGIyZGZi&amp;hl=en_US&quot;&gt;optimistic-concurrency.zip&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;One problem space that fits very well with functional patterns is in developing apps that have to use &lt;a href=&quot;https://jdconley.com/blog/concurrency-its-like-doing-dishes&quot;&gt;optimistic concurrency&lt;/a&gt; to maintain data consistency at scale. Here at Hive7 we build PvP games. In such games, multiple people and background processes are often affecting the same entity at the same time. We can&#39;t use coarse grained locks or high isolation levels in MS-SQL, or the whole game would come to a halt. Here&#39;s a common scenario in a game like &lt;a href=&quot;http://corp.hive7.com/games/knighthood/&quot;&gt;Knighthood&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Image unavailable: archived image (&lt;a href=&quot;http://knight.fb.hive7.com/res/img/area/wall.png?63356112540&quot;&gt;original source&lt;/a&gt;) Multiple rival lords are attacking my Kingdom at once trying to steal my most prized vassal, my wife! My wall is staffed with a heavy defense, and my hospital has a strong set of medics healing my kingdom over time. But to keep a handle on the attack I also have to continuously spend gold to heal my defensive army.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In this common use case there are a number of subtleties. First, multiple people are attacking me at once. That means they&#39;re doing damage to my defenses in real time, and at the same time. My hospital is healing my vassals over time. This occurs in a background process once every few minutes. And I&#39;m triggering an instant heal to my defensive vassals using my gold supply. My Marketplace is also generating gold for me over time in another background process. To top it all off, this is happening across a cluster of application servers that are certain to be processing multiple requests simultaneously. Phew!&lt;/p&gt;
&lt;p&gt;So what does all that mean? Well, basically, there are a lot of possibilities for change conflicts. And we have to deal with those conflicts to both keep a consistent data model and perform well.&lt;/p&gt;
&lt;p&gt;There are a a number of potential strategies for managing these change conflicts in the persistent store – a few beefy Microsoft SQL Server databases in our case. We chose to go with optimistic concurrency and an abort on conflict transaction strategy. That basically means when we write data to the database we make sure we are always writing the most recent version of a row. If an application attempts to write an old version of the row, the data access layer throws an exception and aborts the transaction. Knighthood uses &lt;a href=&quot;http://www.hibernate.org/&quot;&gt;NHibernate&lt;/a&gt; so the validation is done for us automatically using a simple version number on the row. The basic algorithm is:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Read data and serialize into objects (done by NHibernate)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Modify objects in code&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Tell NHibernate to persist the changes, which does the following&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Increments the version number&lt;/li&gt;
&lt;li&gt;Finds all the changes and batches up insert/update calls&lt;/li&gt;
&lt;li&gt;Uses the version number in the WHERE clause of updates like: &quot;UPDATE Table SET Col1=&#39;blah&#39; WHERE Version=36&quot;&lt;/li&gt;
&lt;li&gt;Checks the rows modified reported by SQL server and throws an exception if it&#39;s an unexpected number&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;As you can imagine, this fails regularly in a high concurrency scenario, but it succeeds orders of magnitude more often than not. It&#39;s also pretty standard for any web app nowadays.&lt;/p&gt;
&lt;p&gt;The only problem is, to preserve consistency, an exception is thrown and the transaction is aborted when change conflicts occur. That means whatever request the application or user issued fails. We could show the user a friendly error message, but that would be a frustrating experience. Nobody likes seeing errors for non-obvious reasons. And in the case of headless software running in the background the error would just be in a log somewhere. If it&#39;s something important that needs to happen, then we have to make sure it gets done! So us imperative programmers devise a retry scheme and write a loop with an exception trap around our code. Maybe you get clever and create a class that does this which raises an event any time you need to execute your retry-able code. But, this gets pretty cumbersome. Enter functional programming!&lt;/p&gt;
&lt;p&gt;We have a little class named DataActions that is used to simplify and consolidate this retry process and make it painless to use. I&#39;m going to use LINQ to SQL as the example here. Here&#39;s some usage code:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;DataActions.ExecuteOptimisticSubmitChanges&amp;lt;GameDataContext&amp;gt;(dc =&amp;gt;{    var playerToMod = dc.Players.Where(p =&amp;gt; p.ID == playerId).Single();    SetRandomGold(playerToMod);});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see it&#39;s really straight forward. Notice all the goodness going on there. We don&#39;t have to instantiate our own DataContext, manually submit the changes, or worry at all about transactions. It&#39;s all handled by the wrapper. And, you just have to provide some code to execute once the DataContext has been instantiated.&lt;/p&gt;
&lt;p&gt;The ExecuteOptimisticSubmitChanges helper method itself is pretty simple as well:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public static voidExecuteOptimisticSubmitChanges&amp;lt;TDataContext&amp;gt;(Action&amp;lt;TDataContext&amp;gt; action) where TDataContext : DataContext, new(){ Retry(() =&amp;gt;     {         using (var ts = new TransactionScope())         {             using (var dc = new TDataContext())             {                 action(dc);                 dc.SubmitChanges();                 ts.Complete();             }         }     });}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And, finally, we have the Retry method:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public static void Retry(Action a){ const int retries = 5; for (int i = 0; i &amp;lt; retries; i  ) {     try          {             a();             break;     }     catch         {             if (i == retries - 1) throw;         //exponential/random retry back-off.             var rand = new Random(Guid.NewGuid().GetHashCode());         int nextTry = rand.Next(           (int)Math.Pow(i, 2), (int)Math.Pow(i + 1, 2) + 1);         Thread.Sleep(nextTry);     } }}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When you string all this together you get pseudo-stacks that look like:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;MyCodeExecuteOptimisticSubmitChangesRetry  ExecuteOptimisticSubmitChanges    MyCode
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So, why should you care? The calling code is really easy to read, and you get a number of other benefits with this code. In addition to handling exceptions caused by concurrency errors, you also get retries on deadlocks, and more common Sql Connection errors.&lt;/p&gt;
&lt;p&gt;I put together a little sample application you can play with. It uses these helpers and has a SQL Database with it. The sample simulates really high concurrency and you can watch it deal gracefully with deadlocks. Then you can change line 29 of Program.cs and execute the same concurrent code without retries enabled. It ouputs the number of failed transactions and a bunch of other interesting stuff to the console. Here&#39;s some example output:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; ...  Retrying after iteration 0 in 1ms Retrying after iteration 0 in 0ms Thread finished with 0 failures. Concurrency at 3Retrying after iteration 1 in 3msRetrying after iteration 1 in 4msThread finished with 0 failures. Concurrency at 2Retrying after iteration 2 in 5msThread finished with 0 failures. Concurrency at 1Retrying after iteration 3 in 15msThread finished with 0 failures. Concurrency at 00 total failures and 7 total retries.All done. Hit enter to exit.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And the same test run with retries disabled:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; ...  Starting worker. Concurrency at 8Thread finished with 0 failures. Concurrency at 7Thread finished with 0 failures. Concurrency at 6Thread finished with 1 failures. Concurrency at 5Thread finished with 1 failures. Concurrency at 4Thread finished with 1 failures. Concurrency at 2Thread finished with 2 failures. Concurrency at 3Thread finished with 0 failures. Concurrency at 1Thread finished with 2 failures. Concurrency at 07 total failures and 0 total retries.All done. Hit enter to exit.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here&#39;s the download link again: &lt;a href=&quot;https://docs.google.com/viewer?a=v&amp;pid=explorer&amp;chrome=true&amp;srcid=0B7Ew2HKAAmajMGNmZGNjNTMtYzQwMy00MWJkLTk3MDItODJhYzJjOGIyZGZi&amp;hl=en_US&quot;&gt;optimistic-concurrency.zip&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Let me know if you have any questions.&lt;/p&gt;
</content:encoded><category>architecture</category><category>linq</category><category>utility</category></item>
<item><title>A new basket for my eggs</title><link>https://jdconley.com/blog/new-basket-for-my-eggs</link><guid isPermaLink="false">tag:blogger.com,1999:blog-1741199026308686058.post-6630336472210026047</guid><pubDate>Wed, 03 Jun 2009 06:46:00 GMT</pubDate><description>Hopefully after reading that title you&#39;re thinking of the old adage &quot;Don&#39;t put all your eggs in one basket&quot; and not something crude. Ok, I admit, either way it works for me.…</description><content:encoded>&lt;p&gt;Hopefully after reading that title you&#39;re thinking of the old adage &quot;Don&#39;t put all your eggs in one basket&quot; and not something crude. Ok, I admit, either way it works for me. You&#39;re still reading.&lt;/p&gt;
&lt;p&gt;Let me preface by saying I love what&#39;s going on at Hive7, but a guy&#39;s gotta have a side project. In fact I wrote about &lt;a href=&quot;https://jdconley.com/blog/dont-hire-programmer-if-they-dont-code&quot;&gt;this phenomenon&lt;/a&gt; a while back. And, in my mind, that side project might as well make me some lunch money.&lt;/p&gt;
&lt;p&gt;For the last two years or so I&#39;ve been really interested in digital photos and the untapped markets that lie within. In fact, I got introduced to Hive7 while trying to sell myself to an investor to get some angel funding in the space. I&#39;m not a pro photographer wannabe or anything like that. I just think digital photos are a great medium for sharing life with friends and family. I have built &lt;a href=&quot;http://www.facebook.com/apps/application.php?id=2466327790&quot;&gt;Friend Photosaver&lt;/a&gt; for Facebook (a screen saver using Facebook photos), &lt;a href=&quot;http://www.facebook.com/apps/application.php?id=7515202213&quot;&gt;Photo Feeds&lt;/a&gt; for Facebook (automatic photo RSS creator for Facebook), and &lt;a href=&quot;http://www.facebook.com/apps/application.php?id=5577408502&quot;&gt;Photozap&lt;/a&gt; (a tool to download Facebook photos as a zip file).&lt;/p&gt;
&lt;p&gt;Those applications are all pretty cool, but didn&#39;t really strike me (or anyone else) as especially compelling. But, they did lead me down the path of building something that I think is pretty interesting.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Everyone&lt;/strong&gt; has a digital camera or cell phone camera. When you go to a social gathering of any sort there are usually tens to hundreds of photos taken. Think of weddings, birthdays, graduations, family bbq&#39;s, night clubs. . . . What happens to these photos? Someone copies them to their computer, or uploads them to a photo sharing web site. They send out links or maybe share the photos through a social network&#39;s tagging or posting features or some such. That&#39;s all fine and good, but I think there&#39;s more to be had.&lt;/p&gt;
&lt;p&gt;Enter &lt;a href=&quot;http://www.pixur.me/&quot;&gt;pixur.me&lt;/a&gt;. Quoting the about page:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Pixur.me is a different kind of online photo sharing service. Our mission is to focus on the person receiving photos, rather than the one taking them. There are a lot of great services where you can organize your own photos and share them with people, but we think that&#39;s only half of the equation.&lt;/p&gt;
&lt;p&gt;Can you find all the cute pictures of your kids from your last family vacation? Or how about all the photos from your wedding that your guests took? Could your mother find those same photos?&lt;/p&gt;
&lt;p&gt;You could if your family was using pixur.me! What if all the photos that everyone took at that last vacation or your wedding were in one spot? Even though Aunt Sue uses Flickr, and you use Facebook, and your mother uses Picasa. That&#39;s pixur.me. Create a Stream and see for yourself! Once your stream is created anyone can add photos to it, regardless of where they are stored online.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That&#39;s it. Another basket awaiting some eggs. &lt;a href=&quot;http://www.pixur.me/&quot;&gt;Give it a spin&lt;/a&gt; and let me know what you think. Of course, it&#39;s not very interesting if you just use it by yourself. Create a stream and give out the link at your next gathering. Or maybe start a stream that your extended family can add photos to so grandma can see them all in one spot.&lt;/p&gt;
&lt;p&gt;Oh yeah, I almost forgot this is a technical blog. This project started out as a technology experiment so it&#39;s built on Windows Azure and ASP.NET MVC. Very cool stuff. I&#39;ll have to write more about them later...&lt;/p&gt;
</content:encoded><category>azure</category><category>business</category><category>facebook</category></item>
<item><title>ioDrive, Changing the Way You Code</title><link>https://jdconley.com/blog/iodrive-changing-way-you-code</link><guid isPermaLink="false">tag:blogger.com,1999:blog-1741199026308686058.post-3039767605246329505</guid><pubDate>Thu, 12 Mar 2009 19:30:00 GMT</pubDate><description>Introduction In my lifetime there have been very few technologies that have created a paradigm shift in the software industry – I was born just after the spinning magnetic hard…</description><content:encoded>&lt;p&gt;&lt;a id=&quot;intro&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Introduction&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In my lifetime there have been very few technologies that have created a paradigm shift in the software industry – I was born just after the spinning magnetic hard drive was created. Off the top of my head I can think of: the Internet (thanks Al!), optical disks, Windows, and parallel computing. From each of these technologies entirely new software industries were born and development methodology drastically changed. We&#39;re at the beginning of another such change, this time in data storage.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Contents&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://jdconley.com/blog/iodrive-changing-way-you-code#intro&quot;&gt;Introduction&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://jdconley.com/blog/iodrive-changing-way-you-code#random&quot;&gt;Random Story for Context&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://jdconley.com/blog/iodrive-changing-way-you-code#system&quot;&gt;System Configuration&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://jdconley.com/blog/iodrive-changing-way-you-code#test&quot;&gt;Test Configuration&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://jdconley.com/blog/iodrive-changing-way-you-code#results&quot;&gt;Test Results&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://jdconley.com/blog/iodrive-changing-way-you-code#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a id=&quot;random&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Random Story for Context&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;At &lt;a href=&quot;http://www.hive7.com/&quot;&gt;Hive7&lt;/a&gt; we make web based social games for platforms like Facebook and Myspace. We&#39;re a tiny startup, but producing a successful game on these platforms means we&#39;re writing code to deal with millions of monthly users, and thousands of simultaneous users pounding away at our games. Because our games are web based they&#39;re basically written like you&#39;d write any other web application. They&#39;re stateless, with multiple RDBMS back end servers for most of the data storage. Game state is pretty small so we don&#39;t really store that much data per user. We don&#39;t have Google sized problems to solve or anything. Our main problem is with speed.&lt;/p&gt;
&lt;p&gt;When you&#39;re surfing the web you want it to be fast but can live with a page taking a few second to load here and there. When you&#39;re playing a game, on the other hand, you want instant gratification. A full second is just way too long to wait to see the results of your action. Your character&#39;s life might be on the line!&lt;/p&gt;
&lt;p&gt;To accomplish this speed in our games we currently buy high end commodity hardware for our database servers, and have a huge cluster of memcached that we tap into. It works. But, properly implementing caching is complex. And those DB servers are big 3U power hungry monsters! Here&#39;s a typical disk configuration of one of our DB servers:&lt;/p&gt;
&lt;p&gt;&lt;a id=&quot;BLOGGER_PHOTO_ID_5632593832082979442&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://jdconley.com/blog-assets/imported/52cfc90a61e4ca22231a591c.png&quot;&gt;&lt;img src=&quot;https://jdconley.com/blog-assets/imported/52cfc90a61e4ca22231a591c.png&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Each of those drives are 15k RPM 72 GB SAS (or whatever the fastest is at the time of build). And the RAID controllers are very high end with loads of cache. And here&#39;s the kicker! We can only use about 25% of the capacity of these arrays before the database write load gets too high and performance starts to suffer. They cost us about $10k a piece. Sure, there are much more complex architectures we could use to gain performance. Or we could spend a few hundred grand and pick up a good SAN of some sort. Or we could drop some coin for &lt;a href=&quot;http://www.youtube.com/watch?v=96dWOEa4Djs&amp;fmt=22&quot;&gt;Samsung SSD&#39;s&lt;/a&gt;. But, those options are a bit out of the price we want to spend for our hardware, not to mention the necessary rack space and power requirements.&lt;/p&gt;
&lt;p&gt;Enter the &lt;a href=&quot;http://www.fusionio.com/Products.aspx&quot;&gt;ioDrive&lt;/a&gt;. With read/write speeds that are very close to the 24 SSD monster that Samsung recently touted, at a way lower price, I have a hard time imagining choosing the 24 drive option. Maybe if you had massive storage requirements, but for pure performance you can&#39;t beat the ioDrive price/performance ratio right now. I don&#39;t remember if I&#39;m allowed to comment on pricing, but you can contact a sales rep at Fusion-io for more info.&lt;/p&gt;
&lt;p&gt;Last month we picked up one of these bad boys for testing. In summary, &quot;WOW!&quot; I spent a few hours this week putting the ioDrive through the ringer and comparing it to a couple different disk configurations in our datacenter. My main goal was to see if this is a viable option to help us consolidate databases and/or speed up existing servers.&lt;/p&gt;
&lt;p&gt;&lt;a id=&quot;system&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Configuration&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;ioDrive System (my workstation)&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Windows Server 2008 x64 Standard Edition&lt;/li&gt;
&lt;li&gt;4 CPU Cores&lt;/li&gt;
&lt;li&gt;6 GB Ram&lt;/li&gt;
&lt;li&gt;80 GB ioDrive&lt;/li&gt;
&lt;li&gt;Log and Data files on same drive&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;Fast Disk System&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Windows Server 2008 x64 Standard Edition&lt;/li&gt;
&lt;li&gt;8 CPU Cores&lt;/li&gt;
&lt;li&gt;8 GB Ram&lt;/li&gt;
&lt;li&gt;16 15k RPM 72 GB SAS Drives (visualization above)&lt;/li&gt;
&lt;li&gt;Log and Data files on different arrays&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;Big and Slow Disk System&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Windows Server 2008 x64 Standard Edition&lt;/li&gt;
&lt;li&gt;4 CPU Cores&lt;/li&gt;
&lt;li&gt;8 GB Ram&lt;/li&gt;
&lt;li&gt;12 7200 RPM 500 GB SATA Drives&lt;/li&gt;
&lt;li&gt;Log and Data files on different arrays&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a id=&quot;test&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Test Configuration&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;For this test I used &lt;a href=&quot;http://support.microsoft.com/kb/231619&quot;&gt;SQLIOSim&lt;/a&gt; with two five minute test runs. We were really only interested in simulating database workloads. If you want a more comprehensive set of tests check out &lt;a href=&quot;http://www.tomshardware.com/search.php?s=iodrive&amp;x=0&amp;y=0&quot;&gt;Tom&#39;s Hardware&lt;/a&gt;. I should also mention that this was obviously not a test of equals. Both disk based systems have a clear RAM advantage and the fast disk system has a clear CPU advantage. The hardware chipsets and CPU&#39;s are also slightly different, but they&#39;re the same generation of Intel chips. In any case, when you see the results you&#39;ll see how this had a negligible effect. We&#39;re talking orders of magnitude differences in performance here...&lt;/p&gt;
&lt;p&gt;I ran two different configurations through SQLIOSim. One was the &quot;Default&quot; configuration that ships with the tool. It represents a pretty typical load on a SQL Server disk system for a general use SQL server. The other was one I created called &quot;Write Heavy Memory Constrained&quot;. The write heavy one was designed to simulate the usage in a typical game, where, due to caching, we have way more writes than reads to a database. Also, the write heavy one is much more parallel. It uses 100 simulated simultaneous random access users where the default one has only 8. And, with the write heavy one there is no chance the entire data set can be cached in memory. It puts a serious strain on the disk subsystem.&lt;/p&gt;
&lt;p&gt;I took the output from SQLIOSim and imported it into Excel to do some analysis. I was primarily concerned with two metrics: IO Duration and IO Operation count. These two things tell me all I need to know. First, how long does it take the device to perform IO on average, and how many can it get done in the given time period.&lt;/p&gt;
&lt;p&gt;&lt;a id=&quot;results&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Test Results&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Write Heavy Memory Constrained Workload&lt;/em&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;ioDrive&lt;/th&gt;
&lt;th&gt;Slow Disks&lt;/th&gt;
&lt;th&gt;Fast Disks&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Total IO Operations&lt;/td&gt;
&lt;td&gt;10,625,381&lt;/td&gt;
&lt;td&gt;1,309,673&lt;/td&gt;
&lt;td&gt;3,260,725&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Total IO Time (ms)&lt;/td&gt;
&lt;td&gt;17,625,337&lt;/td&gt;
&lt;td&gt;1,730,147,612&lt;/td&gt;
&lt;td&gt;356,839,912&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cumulative Avg IO Duration (ms)&lt;/td&gt;
&lt;td&gt;1.66&lt;/td&gt;
&lt;td&gt;1,321.05&lt;/td&gt;
&lt;td&gt;109.44&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;a id=&quot;BLOGGER_PHOTO_ID_5632593827268035602&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://jdconley.com/blog-assets/imported/42cc10d05f0d863f21b62370.png&quot;&gt;&lt;img src=&quot;https://jdconley.com/blog-assets/imported/42cc10d05f0d863f21b62370.png&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Wow, 100x faster IO&#39;s on average!&lt;/p&gt;
&lt;p&gt;&lt;a id=&quot;BLOGGER_PHOTO_ID_5632593828024019538&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://jdconley.com/blog-assets/imported/e0338291f4f4b1d0f1597a4e.png&quot;&gt;&lt;img src=&quot;https://jdconley.com/blog-assets/imported/e0338291f4f4b1d0f1597a4e.png&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Over 20x less time spent doing IO operations!&lt;/p&gt;
&lt;p&gt;&lt;a id=&quot;BLOGGER_PHOTO_ID_5632593826144091986&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://jdconley.com/blog-assets/imported/cdaa40da4f577e445a0bce77.png&quot;&gt;&lt;img src=&quot;https://jdconley.com/blog-assets/imported/cdaa40da4f577e445a0bce77.png&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;And over 3x more operations performed. This would have been way higher, but the ioDrive system was CPU constrained, taking 100% CPU. Looks like we&#39;ll be loading up at least 8 cores in any database servers we build with these cards!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Default Workload&lt;/em&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;ioDrive&lt;/th&gt;
&lt;th&gt;Slow Disks&lt;/th&gt;
&lt;th&gt;Fast Disks&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Total IO Operations&lt;/td&gt;
&lt;td&gt;690,753&lt;/td&gt;
&lt;td&gt;287,180&lt;/td&gt;
&lt;td&gt;456,300&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Total IO Time (ms)&lt;/td&gt;
&lt;td&gt;3,616,903&lt;/td&gt;
&lt;td&gt;231,859,576&lt;/td&gt;
&lt;td&gt;93,991,055&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cumulative Avg IO Duration (ms)&lt;/td&gt;
&lt;td&gt;5.24&lt;/td&gt;
&lt;td&gt;807.37&lt;/td&gt;
&lt;td&gt;205.99&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;a id=&quot;BLOGGER_PHOTO_ID_5632593825485629506&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://jdconley.com/blog-assets/imported/84e3aa062bc274fff952e0bf.png&quot;&gt;&lt;img src=&quot;https://jdconley.com/blog-assets/imported/84e3aa062bc274fff952e0bf.png&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;40x faster on average in this workload! Looks like the bulk operations and larger IO&#39;s present in this workload narrowed the gap a bit.&lt;/p&gt;
&lt;p&gt;&lt;a id=&quot;BLOGGER_PHOTO_ID_5632593444295861314&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://jdconley.com/blog-assets/imported/42fc3efdfb886aa95c321d1c.png&quot;&gt;&lt;img src=&quot;https://jdconley.com/blog-assets/imported/42fc3efdfb886aa95c321d1c.png&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This time, a little under 30x less time spent doing IO operations!&lt;/p&gt;
&lt;p&gt;&lt;a id=&quot;BLOGGER_PHOTO_ID_5632593240851024802&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://jdconley.com/blog-assets/imported/6c16f17d34de3564e0fe8a4b.png&quot;&gt;&lt;img src=&quot;https://jdconley.com/blog-assets/imported/6c16f17d34de3564e0fe8a4b.png&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Only 1.5x more total operations this round. This time we weren&#39;t CPU constrained, and I didn&#39;t take the time to dig in to the &quot;why&quot; on this one. Based on the raw data I would guess this is caused by IO blocking a lot more often for ioDrive than the fast RAID system. This probably has to do with the caching system in the RAID cards under this mixed write workload. You&#39;ll notice if you look at the raw report, that the ioDrive has no read or write cache at the device level. It doesn&#39;t really need it.&lt;/p&gt;
&lt;p&gt;In case you want to see the raw data or the SQLIOSim configuration files, you can download the package here: &lt;a href=&quot;https://docs.google.com/viewer?a=v&amp;pid=explorer&amp;chrome=true&amp;srcid=0B7Ew2HKAAmajZjJkNjNkZjItYmRhMS00ZWFlLTlhM2ItMGVkNzZjOGM2NzNk&amp;hl=en_US&quot;&gt;ioDrive Test Results&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a id=&quot;conclusion&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Wow! ioDrive is going to be scary fast in a database server, especially when it comes to tiny random write IO&#39;s, parallelism, and memory constraints. I think we&#39;ll be seeing a lot of new interesting software development and system architectures due to this type of technology. The industry is changing. You no longer need either tons of cache (or cash) or tons of RAM to get great performance out of your data store. We&#39;re talking 100x better performance than our fast commodity arrays. I think it&#39;s safe to say we&#39;ll be using these devices in production in the near future. Since this device is currently plugged into my workstation, maybe I&#39;ll post another review about how it&#39;s improving my development productivity so you can convince your boss to buy you one. :)&lt;/p&gt;
</content:encoded><category>architecture</category><category>tuning</category></item>
<item><title>You might be a great hacker if you...</title><link>https://jdconley.com/blog/you-might-be-great-hacker-if-you</link><guid isPermaLink="false">tag:blogger.com,1999:blog-1741199026308686058.post-8143439452965828995</guid><pubDate>Tue, 10 Feb 2009 03:14:00 GMT</pubDate><description>A number of years ago I was doing some mentoring at a California state agency that shall remain nameless. I got my butt up in time to be into their office at 8am. (Ok, I&#39;ll be…</description><content:encoded>&lt;p&gt;A number of years ago I was doing some &lt;a href=&quot;http://www.kieferconsulting.com/Pages/Mentoring.aspx&quot;&gt;mentoring&lt;/a&gt; at a California state agency that shall remain nameless. I got my butt up in time to be into their office at 8am. (Ok, I&#39;ll be honest, usually I got up in time. I was late on a few occasions.) I led them down the path of learning ASP.NET from scratch. Together we built a great product that is still in use today on a highly trafficked web site. Some time late in the mentoring project a student came up to me and asked the strangest question. He wanted to know how I learned everything I was teaching them. He wanted to take the same classes.&lt;/p&gt;
&lt;p&gt;&lt;a id=&quot;BLOGGER_PHOTO_ID_5632589234957953826&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://jdconley.com/blog-assets/imported/06a43d6af5469f401d91f551.jpg&quot;&gt;&lt;img src=&quot;https://jdconley.com/blog-assets/imported/72fd0c21a6c286157dc3ecc2.jpg&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The guy was an amazing engineer. He was methodical, had great documentation, dotted all his i&#39;s and crossed all this t&#39;s. But he wasn&#39;t a &lt;a href=&quot;http://www.paulgraham.com/gh.html&quot;&gt;great hacker&lt;/a&gt;. He was a bit slow, and didn&#39;t have much creativity. It was around that time I started paying more attention to traits of great hackers, before Paul coined the term. The bastard! At that time I was really just looking for people that learned quickly and could get things done faster than the rest. Some day maybe I&#39;ll figure out how to be all witty and important and coin terms.&lt;/p&gt;
&lt;p&gt;So, here we go, in no particular order – except the first one, which is the obvious transition from my enticing story above:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;started off as a script kiddie&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A typical scenario looks something like the following, though could occur in any area (not just video games):&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Play Quake 2&lt;/li&gt;
&lt;li&gt;Get stupidly good at Quake 2&lt;/li&gt;
&lt;li&gt;Get bored with Quake 2&lt;/li&gt;
&lt;li&gt;Figure out how to cheat by writing scripts to rocket jump or speed hack&lt;/li&gt;
&lt;li&gt;Realize what you just did was coding, and it&#39;s fun and amazingly rewarding&lt;/li&gt;
&lt;li&gt;Change all direction in life (yes, even when you&#39;re 12 years old) so you can do more coding&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;often forget to shave&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&quot;Wait a minute, you mean people do their &lt;em&gt;own&lt;/em&gt; laundry?&quot; Yes, you are exceptionally lazy. That&#39;s ok. You have more important things to do in life than worry about how you smell/look.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;have ever worked on a project for 24 hours straight&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&quot;Hold on! You don&#39;t work without sleep until a problem is solved?&quot; And no, last minute procrastination doesn&#39;t count, and neither do production outages. Everyone&#39;s been there. I&#39;m talking about all night sessions working to solve a problem that could have been done over a few normal working days&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;instantly quiet a room when you speak&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;You don&#39;t talk much. You spend most of your time listening to others. You find idle chit chat to be boring and have quantitatively determined it&#39;s a waste of time. Maybe it&#39;s because you don&#39;t have much to say. But, what I think is more likely is that you only say things that are relevant and important. Thus, when you speak, the room listens. A room full of strangers doesn&#39;t count. They won&#39;t know you only say important things until you&#39;ve trained them that way.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;have ever gone to visit a friend and proceeded to ignore them because you must finish that stupid puzzle they had on their coffee table before putting it down&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;See photo at top of post.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;get asked to help debug other people&#39;s code&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;There&#39;s a certain amount of pride a developer has over their code. No matter how logical it is to call someone in for help, it&#39;s always the last thing we do. If you&#39;re the guy people call for help, you&#39;re on the right track.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;are naturally good at video games&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Ever pick up a game, and within minutes beat or come really close to beating, someone who&#39;s been playing it for months? This is a sure fire sign of your analytical and problem solving skills. Come to think of it, I think I&#39;m going to start adding this to my interview process.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;use every operating system in existence&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Sure, you think Windows sucks, but you use it because you play games on it and deep inside you know it doesn&#39;t really suck much worse than the competition. You know Linux is the best (DUH!) but you play with FreeBSD. You have OSX running on your laptop because those big icons and MacBooks are sexy. But really, it&#39;s more about curiosity than anything.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;make a habit of picking up a new technology over the weekend&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Lego Mindstorms, anyone? Oooh, how about Adobe AIR or Microsoft Azure or iPhone development. You catch my drift.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;are extremely critical of everything&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;You find fault in everything from your takeout food to web sites to world economic systems. The world is an imperfect mess that needs to be cleaned up. And, of course, you could do it with a weekend and your new favorite development platform (that you haven&#39;t used yet)!&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is all I could come up with in the time I set aside for this blog post. So what do you all think? What am I missing? I&#39;ll update the post with your ideas as they come in, if they don&#39;t suck.&lt;/p&gt;
</content:encoded><category>random</category></item>
<item><title>Abstracting Away Azure: How to Run Outside of the Cloud</title><link>https://jdconley.com/blog/abstracting-away-azure-how-to-run</link><guid isPermaLink="false">tag:blogger.com,1999:blog-1741199026308686058.post-6581387070107928666</guid><pubDate>Tue, 03 Feb 2009 00:27:00 GMT</pubDate><description>I had a lot of fun over our holiday break this December working on prototype projects for up and coming technologies. One of those projects dealt with Windows Azure, or, the…</description><content:encoded>&lt;p&gt;I had a lot of fun over our holiday break this December working on prototype projects for up and coming technologies. One of those projects dealt with Windows Azure, or, the Azure Services Platform. Azure is basically a cloud application hosting environment put together by Microsoft. The idea is, you build your web apps in .NET and publish them to the nebulous cloud. Once in the cloud they scale and perform well and you don&#39;t have to deal with any of the headaches of managing things at the OS/System level.&lt;/p&gt;
&lt;p&gt;But with the recent &lt;a href=&quot;http://www.microsoft.com/presspass/press/2009/jan09/01-22fy09Q2earnings.mspx&quot;&gt;economic news&lt;/a&gt; out of Redmond I&#39;ve been wondering about the future of its more experimental CTP/Alpha/Omega/Whatever-They-Call-It projects such as Azure. If you&#39;re not familiar with the project, I suggest you &lt;a href=&quot;http://www.microsoft.com/azure/default.mspx&quot;&gt;venture on over&lt;/a&gt; and check it out now.&lt;/p&gt;
&lt;p&gt;Unlike other cloud hosting platforms out there, with Azure you don&#39;t have to maintain the operating system. Not only do you get the benefits of cloud computing, but you don&#39;t even need a system administrator to run the thing. Of course, the fact that you don&#39;t have control of the operating system has its drawbacks.&lt;/p&gt;
&lt;p&gt;With Azure you can&#39;t run unmanaged code, you&#39;re stuck in Medium trust, and you can only build a port 80/443 HTTP application. If you want to run memcached or Velocity or streaming media codecs, well, you can&#39;t. If you want to host a game server that communicates with UDP or some non-http protocol, you can&#39;t do that either. But, for most custom web applications, everything you need is there. They host a &quot;database&quot; for you, a queue service, you can run background services, and you even get a shared logging service.&lt;/p&gt;
&lt;p&gt;All of the services they provide seem to work as advertised and are promised to be extremely scalable. But, one thing they don&#39;t talk about (and I can&#39;t say I blame them) is how you might run your applications if they&#39;re not hosted in the cloud. In our company this just isn&#39;t acceptable. If we put out a game and our hosting provider ceases to exist, or no longer meets our needs, we had better be able to move to a new hosting provider! So, I&#39;ll give you some tips based on my experiences building prototype Azure applications on how you can easily easily design your applications to run outside of the cloud.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Main Azure Features&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Table storage&lt;/li&gt;
&lt;li&gt;Queue services&lt;/li&gt;
&lt;li&gt;Blob storage&lt;/li&gt;
&lt;li&gt;Logging&lt;/li&gt;
&lt;li&gt;Background services (Worker Role)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Table/Queue/Blob&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Abstracting away tables, queues, and blobs is fairly simple but takes a bit of up front planning. You do basically the same thing you&#39;d do if you were building an application on a large team that is designed to work with any data storage back end. At a high level:&lt;/p&gt;
&lt;p&gt;&lt;a id=&quot;BLOGGER_PHOTO_ID_5632587561430323474&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://jdconley.com/blog-assets/imported/545427e849e19249bb213df0.png&quot;&gt;&lt;img src=&quot;https://jdconley.com/blog-assets/imported/545427e849e19249bb213df0.png&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;In order to maintain the abstraction it&#39;s very important that your UI and background services don&#39;t interact directly with the Azure services. First off, use &lt;a href=&quot;http://en.wikipedia.org/wiki/Data_Transfer_Object&quot;&gt;DTO&lt;/a&gt; entities. If all else fails and your new back end storage isn&#39;t compatible with Azure, you can always fall back to re-writing the layer that talks to it and you don&#39;t have to change any of your UI code. &lt;strong&gt;Do not&lt;/strong&gt; expose the PartitionKey and RowKey values on your DTO entities. Leave the partitioning scheme as an implementation detail of your Service/Model layer. It will change if you have to move your data into Amazon&#39;s &lt;a href=&quot;http://aws.amazon.com/simpledb/&quot;&gt;SimpleDB&lt;/a&gt;, for example. Since Azure Table Storage uses the &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/aa697427%28VS.80%29.aspx&quot;&gt;ADO.NET Entity Framework&lt;/a&gt; at the core, there actually isn&#39;t much you need to do to the entities in order to make them portable to other Table-like storage systems. Also, the Blob and Queue storage services are quite simple and abstracting their interface is a matter of tens of lines of code.&lt;/p&gt;
&lt;p&gt;Create interfaces for the layer that the UI communicates with and use a &lt;a href=&quot;http://en.wikipedia.org/wiki/Dependency_injection&quot;&gt;dependency injection&lt;/a&gt; (DI) framework such as &lt;a href=&quot;http://structuremap.sourceforge.net/&quot;&gt;StructureMap&lt;/a&gt; or &lt;a href=&quot;http://www.castleproject.org/&quot;&gt;Castle&lt;/a&gt; to inject your implementations that communicate with Azure.&lt;/p&gt;
&lt;p&gt;I use StructureMap on a day to day basis, and I was dissapointed that it didn&#39;t work out of the box. I had to make a couple modifications to the source to get it to run under medium trust. First, you need to add an AllowPartiallyTrustedCallersAttribute to the assembly and then remove the security assertion that&#39;s asserting the right to read the machine name (you don&#39;t have access to the machine name in medium trust). You can download my updated version here (patch and binary): &lt;a href=&quot;https://docs.google.com/viewer?a=v&amp;pid=explorer&amp;chrome=true&amp;srcid=0B7Ew2HKAAmajNzVkNjlmNGMtYTAxNS00MGU0LTk0MjctN2U4Yzg3NTMxYmRh&amp;hl=en_US&quot;&gt;StructureMap-2.5-PartialTrust.zip&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;That&#39;s it. With your UI not talking directly to the Azure services you&#39;ll have an extra layer of code to maintain, but you&#39;ll be thankful if you ever need to pull it out of the cloud.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Logging&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;For all my non-Azure projects I use &lt;a href=&quot;http://logging.apache.org/log4net/&quot;&gt;log4net&lt;/a&gt; for logging. It&#39;s a simple, flexible, open-source logging engine. You might want to use Enterprise Framework. Whatever. Just like with the storage engines the key to being able to move off of the Azure logging service some day is to not use it in your applications directly. I wrote a little Appender plugin for log4net that writes logs to the Azure RoleManager if the app is loaded into the Azure context. Most of the code is mapping the multitude of log4net log levels to the Azure event log names. Here&#39;s the code:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public class AzureRoleManagerAppender: AppenderSkeleton{public AzureRoleManagerAppender(){}public AzureRoleManagerAppender(ILayout layout){   Layout = layout;}protected override void Append(log4net.Core.LoggingEvent loggingEvent){   if (null == Layout)       Layout = new log4net.Layout.SimpleLayout();   var sb = new StringBuilder();   using (var sr = new StringWriter(sb))   {       Layout.Format(sr, loggingEvent);       sr.Flush();       if (RoleManager.IsRoleManagerRunning)           RoleManager.WriteToLog(GetEventLogName(loggingEvent), sb.ToString());       else           System.Diagnostics.Trace.Write(sb.ToString(), GetEventLogName(loggingEvent));   }}protected virtual string GetEventLogName(LoggingEvent loggingEvent){   if (loggingEvent.Level == Level.Alert)       return &quot;Critical&quot;;   else if (loggingEvent.Level == Level.Critical)       return &quot;Critical&quot;;   else if (loggingEvent.Level == Level.Debug)       return &quot;Verbose&quot;;   else if (loggingEvent.Level == Level.Emergency)       return &quot;Critical&quot;;   else if (loggingEvent.Level == Level.Error)       return &quot;Error&quot;;   else if (loggingEvent.Level == Level.Fatal)       return &quot;Critical&quot;;   else if (loggingEvent.Level == Level.Fine)       return &quot;Information&quot;;   else if (loggingEvent.Level == Level.Finer)       return &quot;Information&quot;;   else if (loggingEvent.Level == Level.Finest)       return &quot;Information&quot;;   else if (loggingEvent.Level == Level.Info)       return &quot;Information&quot;;   else if (loggingEvent.Level == Level.Notice)       return &quot;Information&quot;;   else if (loggingEvent.Level == Level.Severe)       return &quot;Critical&quot;;   else if (loggingEvent.Level == Level.Trace)       return &quot;Verbose&quot;;   else if (loggingEvent.Level == Level.Verbose)       return &quot;Verbose&quot;;   else if (loggingEvent.Level == Level.Warn)       return &quot;Warning&quot;;   else       return &quot;Information&quot;;}}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then you just configure log4net as usual, and go on your merry way. Write your logs to log4net rather than to the Azure log manager.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;log4net&amp;gt;&amp;lt;appender name=&quot;azure&quot; type=&quot;AzureRoleManagerAppender,MyAssembly&quot;&amp;gt;&amp;lt;layout type=&quot;log4net.Layout.PatternLayout&quot;&amp;gt; &amp;lt;conversionPattern value=&quot;%logger - %message&quot; /&amp;gt;&amp;lt;/layout&amp;gt;&amp;lt;/appender&amp;gt;&amp;lt;root&amp;gt;&amp;lt;level value=&quot;ALL&quot; /&amp;gt;&amp;lt;appender-ref ref=&quot;azure&quot; /&amp;gt;&amp;lt;/root&amp;gt;&amp;lt;/log4net&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;private ILog _log = LogManager.GetLogger(typeof(WorkerRole));..._log.Info(&quot;Starting worker process&quot;);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Background Services&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Background services (Worker Roles) are basically Windows Services. The key difference, though, is in the behavior of the Start method. In Windows Service land you&#39;re expected to exit the Start method when the service has started. In Azure, the Start method is more like a Main and when it exits Azure assumes your service has completed its task and is restarted. I&#39;d just write all your code in your RoleEntryPoint and not worry about any abstraction for the Worker Role. It&#39;s simple enough to just refactor and move to a Windows Service model if need be. But, just like in your UI, don&#39;t communicate directly with Azure back end services like Table, Queue, and Blob storage.&lt;/p&gt;
&lt;p&gt;So there you have it. The basics of abstracting away Azure. I don&#39;t think Microsoft plans on canceling this project any time soon, but if they do (or you want to host elsewhere) you&#39;ll be ready! I, for one, am really excited about the future potential of Azure and we may even use it here, but we will be designing our applications so they can easily be ported to a different platform just in case.&lt;/p&gt;
</content:encoded><category>architecture</category><category>azure</category></item>
<item><title>Put down the abstract factory and get something done</title><link>https://jdconley.com/blog/put-down-abstract-factory-and-get</link><guid isPermaLink="false">tag:blogger.com,1999:blog-1741199026308686058.post-7314456103484989963</guid><pubDate>Mon, 26 Jan 2009 20:58:00 GMT</pubDate><description>It seems as a group, us programmers have our priorities screwed up. Programmers value clean, concise code. Code that requires no documentation. Code that perfectly uses design…</description><content:encoded>&lt;p&gt;It seems as a group, us programmers have our priorities screwed up. Programmers value clean, concise code. Code that requires no documentation. Code that perfectly uses design patterns and best practices. Code that other programmers will look at and think &quot;wow, I wish I was as l33t as this guy.&quot;&lt;/p&gt;
&lt;p&gt;But, let&#39;s get real. That stuff &lt;em&gt;doesn&#39;t matter&lt;/em&gt; .&lt;/p&gt;
&lt;p&gt;Why do you write code? Well, chances are someone pays you to do it. Of course the best programmers also love what they do and do it for fun. But at the end of the day it&#39;s your profession. Maybe you&#39;re (un)lucky enough to be doing it for yourself in your own startup.&lt;/p&gt;
&lt;p&gt;In the early years of a startup only one thing should matter to a programmer: shipping your product to meet your customers&#39; needs. Everything else we do is simply a result of this, the humblest of goals. Without the product people want you have no revenue. Without the revenue you have no company. Without the company, well, you get the idea.&lt;/p&gt;
&lt;p&gt;Startups are widely considered the purest form of a company. You exist to meet a perceived need with a pretty small scope. There aren&#39;t layers of management or TPS reports to get in the way of getting things done. The only barrier to getting something done is yourself. No excuses. It is in this environment where an engineer&#39;s need for perfection must be replaced with a hacker&#39;s passion to get things done, and get them done fast. Nothing else matters.&lt;/p&gt;
&lt;p&gt;Maintainability isn&#39;t a factor. Best practices don&#39;t matter. Design patterns don&#39;t matter. All that matters is getting things done. Don&#39;t worry about scalability until you have to. Instantiate that object. Who cares about the factory. Skip the interface, and create a static class. Some day if you need the interface come back and &lt;em&gt;re-factor your code&lt;/em&gt; . With the power of the IDE these days re-factoring is a lot less scary than it used to be.&lt;/p&gt;
&lt;p&gt;This may sound short sighted, and it is. In fact, that&#39;s the point. Who knows if the company will even exist in a year to have anything to maintain. Projects change. You have to adapt. You will never know how your code will be used 5 years from now. Stop thinking about it. 5 years ago did you think you&#39;d be integrating your [random business application] with this Facebook thing? I bet you&#39;ve thought about it now. Not to mention, 5 years from now it&#39;s likely the entire programming paradigm will have changed. Were they thinking about AJAX when they designed ASP.NET? How about 3D graphics in desktop applications when the window message pump was developed? Such is life in our fast paced world. No amount of overly designed or perfectly formatted code will change it.&lt;/p&gt;
&lt;p&gt;If you find yourself maintaining this horribly designed, hacked together legacy code from the early days of a company be thankful and bask in its glory. Without that spaghetti nightmare you wouldn&#39;t have that job. It was that short sighted thinking that was able to get something done and create a profitable product/company.&lt;/p&gt;
&lt;p&gt;Of course, I&#39;m not advocating you just toss all your code in a button&#39;s click event or anything that silly. Be smart, organize things well, but don&#39;t waste time overly designing code to be flexible. If you have to spend more than a couple hours sketching out your design, it&#39;s probably too complicated. Write some code. Re-factor it if you need to. You don&#39;t need a proper &lt;a href=&quot;http://en.wikipedia.org/wiki/Representational_State_Transfer&quot;&gt;RESTful architecture&lt;/a&gt;, or a perfect &lt;a href=&quot;http://en.wikipedia.org/wiki/Domain-driven_design&quot;&gt;DDD&lt;/a&gt;. Your application isn&#39;t going to change from Microsoft SQL to MySQL some day.&lt;/p&gt;
&lt;p&gt;Alright, I&#39;ll admit it. If you&#39;re building enterprise server products, or work on a large team, or are building framework products for developers to use, then ignore everything I&#39;ve said. Of course, then I&#39;d question why you&#39;re a startup in that position in the first place....&lt;/p&gt;
&lt;p&gt;So I urge you, especially if you&#39;re in a startup, to put down put down the abstract factory and get something done.&lt;/p&gt;
</content:encoded><category>business</category></item>
<item><title>Concurrency. It&#39;s like doing the dishes</title><link>https://jdconley.com/blog/concurrency-its-like-doing-dishes</link><guid isPermaLink="false">tag:blogger.com,1999:blog-1741199026308686058.post-3845481521114917521</guid><pubDate>Tue, 20 Jan 2009 18:22:00 GMT</pubDate><description>Since we moved to Palo Alto I&#39;ve had the luxury of walking to work every day. Usually that&#39;s where I do my deep thinking. By the time I cruise by the Whole Foods it&#39;s really…</description><content:encoded>&lt;p&gt;Since we moved to Palo Alto I&#39;ve had the luxury of walking to work every day. Usually that&#39;s where I do my deep thinking. By the time I cruise by the Whole Foods it&#39;s really easy to ignore the activist-of-the-day petitioning something about global warming. But yesterday was different.&lt;/p&gt;
&lt;p&gt;My walks to and from work were pretty normal. When I got home I decided to clean up a bit around the house, was doing the dishes, and had an odd moment of clarity. I threw down the sponge and ran over to my laptop to jot this down.&lt;/p&gt;
&lt;p&gt;Usually I&#39;m at a loss for analogy when explaining how concurrency works to a developer who has never had to deal with it before. So I throw out all kinds of highly technical terms and their eyes glaze over. But you know, it&#39;s actually really simple.&lt;/p&gt;
&lt;p&gt;&lt;a id=&quot;BLOGGER_PHOTO_ID_5632583287208177266&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://jdconley.com/blog-assets/imported/6d6ec83c329ac21f37a87801.jpg&quot;&gt;&lt;img src=&quot;https://jdconley.com/blog-assets/imported/e1a7ffa8f735273bd4df49bc.jpg&quot; alt=&quot;&quot;&gt;&lt;/a&gt;Managing concurrency is like doing the dishes. You can hand wash everything and be sure it gets cleaned perfectly every time or you can stick the dishes straight into the dish washer and take your chances. Most of the time everything will come out clean, but every couple loads you&#39;ll get a dish you need to wash again. Going straight into the dishwasher is way faster, and you can even do more than one dish at a time (assuming you have two hands).&lt;/p&gt;
&lt;p&gt;If you want the technical description, I leave that as an excercise to the reader. Here&#39;s a &lt;a href=&quot;http://en.wikipedia.org/wiki/Optimistic_concurrency_control&quot;&gt;Wikipedia&lt;/a&gt; article. And another over at &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/aa0416cz%28VS.71%29.aspx&quot;&gt;Microsoft&lt;/a&gt; that&#39;s specific to database concurrency. See, told ya it&#39;s like doing the dishes.&lt;/p&gt;
</content:encoded><category>random</category></item>
<item><title>Don&#39;t hire a programmer if they don&#39;t code for fun</title><link>https://jdconley.com/blog/dont-hire-programmer-if-they-dont-code</link><guid isPermaLink="false">tag:blogger.com,1999:blog-1741199026308686058.post-4135665883135653249</guid><pubDate>Mon, 19 Jan 2009 18:39:00 GMT</pubDate><description>I&#39;m not the first person to talk about this paradigm and I won&#39;t be the last. Every single programmer I&#39;ve seen that is exceptionally good at their job also does it for fun.…</description><content:encoded>&lt;p&gt;I&#39;m not the first person to talk about this paradigm and I won&#39;t be the last. Every single programmer I&#39;ve seen that is &lt;em&gt;exceptionally good at their job&lt;/em&gt; also does it for fun. They have an itch. It must be scratched. No matter how fun and lenient the work place, they always have their own project to work on. Their own passion. But, I think there is more to it, or I&#39;d just site some previous articles and be done with it.&lt;/p&gt;
&lt;p&gt;But first, what do I mean by &lt;em&gt;exceptionally good at their job&lt;/em&gt; ? Well, Steve McConnell has made quite a name for himself in recent history bringing forth the research on &lt;a href=&quot;http://blogs.construx.com/blogs/stevemcc/default.aspx&quot;&gt;10x Software Development&lt;/a&gt;. This is the level of exceptional I&#39;m talking about. The guy that takes a 10 minute set of verbal requirements, extrapolates, and builds a Web 4.0 Whooziwhatsit in a day, before you even know what Web 4.0 is. Paul Graham calls these guys &lt;a href=&quot;http://www.paulgraham.com/gh.html&quot;&gt;great hackers&lt;/a&gt;, Joel Spolsky says they&#39;re &lt;a href=&quot;http://www.joelonsoftware.com/items/2007/06/05.html&quot;&gt;smart and get things done&lt;/a&gt;. We just call them rock stars.&lt;/p&gt;
&lt;p&gt;But, to possibly be a rock star, it&#39;s not enough for the programmer to just have a side project. The side project has to be fun (for them). Maybe they get a kick out of programming Lego Mindstorms to walk their chinchilla or creating an app for their mobile phone that synthesizes unique farting noises for ring tones based on the names in their address book. Whatever it is, they should be doing it for the pure joy they get by flexing their creative muscle.&lt;/p&gt;
&lt;p&gt;Next time you&#39;re doing a phone interview ask the candidate about side projects early in the call. Dig in a little bit. Expect the rock star to change her mood and instantly become a lot more talkative. The passion will be self evident. If it isn&#39;t, this person isn&#39;t your rock star.&lt;/p&gt;
&lt;p&gt;Obviously fun coding projects aren&#39;t the only indicator of a rock star, but they&#39;re a good way to filter out programmers that just do it for a paycheck.&lt;/p&gt;
</content:encoded><category>business</category></item>
<item><title>ASP.NET MVC sucks and so does jQuery and PHP</title><link>https://jdconley.com/blog/aspnet-mvc-sucks-and-so-does-jquery-and</link><guid isPermaLink="false">tag:blogger.com,1999:blog-1741199026308686058.post-7640307391466323137</guid><pubDate>Sat, 17 Jan 2009 06:46:00 GMT</pubDate><description>Apparently, saying something sucks gets you a lot of hits. I think I&#39;ll use this tactic more often. My post on 10 Reasons ASP.NET Webforms Suck has been quite the talk in our…</description><content:encoded>&lt;p&gt;Apparently, saying something sucks gets you a lot of hits. I think I&#39;ll use this tactic more often. My post on &lt;a href=&quot;https://jdconley.com/blog/10-reasons-aspnet-webforms-suck&quot;&gt;10 Reasons ASP.NET Webforms Suck&lt;/a&gt; has been quite the talk in our tiny little .NET blog world this week. Who knew you all had such strong opinions on the matter!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;ASP.NET doesn&#39;t &lt;em&gt;completely&lt;/em&gt; suck&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Saying something sucks doesn&#39;t mean it isn&#39;t good enough, or isn&#39;t the best option. In my mind everything sucks. My cell phone sucks, my laptop sucks, my operating system sucks, my car sucks. They all need improvements. They are all far from perfect. It is this mindset that drives me to build better software. If you can&#39;t see the flaws around you how can you improve on them? ASP.NET 4.0 didn&#39;t come around for fun. It came around because 3.5 sucks and needs improvement, and so on, and so forth.&lt;/p&gt;
&lt;p&gt;Quite a few of you wrote some great rebuttals. Some were utter nonsense, but hey, this is the internet. That&#39;s to be expected. I&#39;d like to talk about my favorite comments:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;It&#39;s obviously not a perfect design, but, it did it&#39;s job.&quot; – Robert Sweeney&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Indeed, my thoughts exactly. It did its job. The internet has moved along really fast. Webforms are lagging behind a bit. Sure, it&#39;s still perfect for RAD business type applications. But build a web game on it, or a &quot;Web 2.0&quot; web site, or other consumer facing web product. The level of customization you end up doing to work within the bounds of the framework&#39;s abstraction starts to become silly.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;I agree that is does suck now.&quot; ... &quot;over time, better ways to do things are created and naturally, the old ways get laid to rest&quot; – shaun&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Yeah, this is the nature of things. The technology will be around forever, but the development world will pass it by. We like shiny new things.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;Anyway, this &#39;hidding how HTTP works&#39; philosophie that ASP.NET follows in every single corner of the framework is the real problem. Django, Ruby on Rails, and PHP doesn&#39;t try to hide the fact that you are building a website/page/app and help you in the process of coding with helpers, decorators or simple functions.&quot; – Angel&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;YES! HTTP, HTML, CSS, Javascript. These are the technologies we work with on the web. They&#39;re simple. Learn them, love them, embrace them. It&#39;ll also make your skills a lot more transferable should you ever be looking for work.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;Newb&quot; – rabbit&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;pwned!&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;loooks like newly migrated from php/java.&quot; – web spider&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Did you read my post? I have been using ASP.NET since it was in beta. I live and breathe this stuff and use it every day. I&#39;m simply pointing out the flaws I see.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;I&#39;ve used PHP, Drupal, Rails and even FastCGI in the bad old early days and find I&#39;m always coming back ASP.Net. Security, data abstraction layers, controls, validation, scalability, application recycling, caching, session management and great development/debugging environments are just to hard to pass up.&quot; – Mike&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Yeah, I love ASP.NET too. I don&#39;t use anything else on a serious basis. You definitely mentioned my favorite parts of it, especially the last one.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;This model has been created back in what 1999/ 2000 when MS started working on .NET 1.0 (was released in 2002). So we are talking the model/architecture is almost a decade old, way before the Web 2.0/Ajax days.&quot; – Bart Czernicki&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Yes! It&#39;s old (mature as some say)! Is it at all possible there is a better way now?&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Chris Vanderheyden said &lt;a href=&quot;https://jdconley.com/blog/10-reasons-aspnet-webforms-suck#128&quot;&gt;a lot&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&quot;Honestly, after more than 8 years of professional experience: YES, your SHOULD be out of that highschool mentality. (Look my editor can do only 2 colors i am so L33T...) &quot;&lt;/p&gt;
&lt;p&gt;&quot;I am a developer, i write logic, not translations. I WANT my HTML abstracted. I don&#39;t want to write zeroes and ones down to the NIC now do i. &quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Since you likely know me only from my &#39;it sucks&#39; post, you&#39;re going to find this shocking. I agree with most of the justifications you made (except the ones I listed above). My biggest beef is with your comment on my #1. You obviously have no sense of humor. ;) And, why wouldn&#39;t you want to write html? It&#39;s a simple human readable markup language, not binary networking protocols. XHTML+CSS is abstraction at its best. In fact it&#39;s usually just as simple as the abstractions provided by ASP.NET controls. I mean, really, can you actually point at one of your ASP.NET apps that would run outside of the context of your modern web browser? Something other than html 4.0 or whatever you&#39;re using? You have to learn a lot about the quirks of ASP.NET to get things done well. Why not learn the quirks in html/css/js? Oh wait, you &lt;em&gt;do&lt;/em&gt; have to do that too. The leaky abstraction abounds.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;I only have 1 reason... Leaky abstraction over HTTP that introduces instead of removing complexity. Every other reason is a derivative or effect of this one reason&quot; – Greg Young&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Thanks Greg. You always have a nice way of distilling things down. But that wouldn&#39;t make nearly as fun of a blog post!&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;I think that JD Conley is just sarcastic. Actually he loves .NET&quot; - br_other&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;No, I&#39;m not being sarcastic. Perhaps dramatic. Yes, I love .NET. But it&#39;s not without its flaws.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;sos un boludo&quot; – Sebastian&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is cooler than the &quot;newb&quot; comment! Thrasing in a foreign language!&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;You don&#39;t have to use &amp;lt;%= ClientID%&amp;gt; stuff at all There is a much better way. I claim ASP.NET webforms has the &quot;best&quot; integration with client side DOM. You think I am kidding ? Have you ever heard IScriptControl ? I guess you didn&#39;t&quot; – onur&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Indeed I have heard of IScriptControl and use it quite a bit. It&#39;s an interesting and often useful abstraction. Though I always laugh at myself since to use it I add some C# code to generate some js code to call some other js code I could have just called in the first place if I were working in the markup.&lt;/p&gt;
&lt;p&gt;And finally, we have the people who decided to write a full rebuttal on their slice of the net. Cool. Thanks for the link backs! Hope you enjoyed my comments.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://azamsharp.com/Posts/161_ASP_NET_WebForms_DO_NOT_SUCK_.aspx&quot;&gt;ASP.NET WebForms DO NOT SUCK&lt;/a&gt; – Mohammad Azam&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://ra-ajax.org/mythbusters-busting-the-myths-about-webcontrols.blog&quot;&gt;Mythbusters – Busting the myths about WebControls&lt;/a&gt; – Thomas Hansen&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://leedumond.com/blog/10-reasons-asp-net-webforms-still-rock/&quot;&gt;10 Reasons ASP.NET Webforms (Still) Rock&lt;/a&gt; – Lee Dumond&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;http://mikepope.com/blog/AddComment.aspx?blogid=2092&quot;&gt;Mike Pope&lt;/a&gt; also posted an interesting commentary on the matter. Us silly kids and our toys! Aren&#39;t we allowed to change our minds, backpedal, or get excited by new technology?&lt;/p&gt;
&lt;p&gt;Happy hacking!&lt;/p&gt;
</content:encoded><category>asp.net</category></item>
<item><title>Fire and Forget Email, Webservices and More in ASP.NET</title><link>https://jdconley.com/blog/fire-and-forget-email-webservices-and</link><guid isPermaLink="false">tag:blogger.com,1999:blog-1741199026308686058.post-6717842052803519212</guid><pubDate>Thu, 15 Jan 2009 06:19:00 GMT</pubDate><description>Often times when you&#39;re working on a web site you want to fire and forget an email, a web method or, most common in our case, a Facebook call. There&#39;s a good chance there&#39;s a…</description><content:encoded>&lt;p&gt;Often times when you&#39;re working on a web site you want to fire and forget an email, a web method or, most common in our case, a Facebook call. There&#39;s a good chance there&#39;s a Framework method available to do that for you quite simply. They&#39;re suffixed with the word Async. For email there&#39;s the &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/system.net.mail.smtpclient.aspx&quot;&gt;System.Net.Mail.SmtpClient&lt;/a&gt; class. The following dirt simple code will send an email for you asynchronously:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.google.com/viewer?a=v&amp;pid=explorer&amp;chrome=true&amp;srcid=0B7Ew2HKAAmajN2MzNDEwMTEtZTU5Ny00NjBiLWIyODQtYTdjZjc3M2UzMTEy&amp;hl=en_US&quot;&gt;Download&lt;/a&gt; the sample code&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var s = new SmtpClient();s.SendCompleted +=  (sender2, e2) =&amp;gt;  {      //do something when the send is done.      //retry if error, etc.  };s.SendAsync(from.Text, to.Text, &quot;&quot;, message.Text, null);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Well, that&#39;s pretty darn simple! Create a new SmtpClient. Call SendAsync and pass in your message data. Cool. There&#39;s even a whole set of classes to help you with attachments, multiple formats (like html and text), etc. From your console app or Windows Service this will work beautifully! The problem is, in an ASP.NET page this won&#39;t work. If you do this in a Page_Load or button click event, for example, you&#39;ll get the following helpful error message.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Asynchronous operations are not allowed in this context. Page starting an asynchronous operation has to have the Async attribute set to true and an asynchronous operation can only be started on a page prior to PreRenderComplete event.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Basically what ASP.NET is saying is that it&#39;s not prepared for you to make an Async call. No problem! ASP.NET has a nifty page directive. Just set Async=&quot;True&quot;. The MSDN documentation says: &quot;Makes the page an asynchronous handler (that is, it causes the page to use an implementation of IHttpAsyncHandler to process requests).&quot; What does that mean? Well, there are a whole bunch of posts on this, so if you&#39;re not familiar, search around for &lt;a href=&quot;http://www.google.com/search?q=asp.net+async+page&quot;&gt;asp.net async page&lt;/a&gt; and come back here. Also do a search for &quot;async&quot; in my blog. I&#39;ve posted about it a lot. It&#39;s one of my favorite features in ASP.NET.&lt;/p&gt;
&lt;p&gt;So, now you&#39;ve got the Async page directive down and you think all is good. But then, suddenly, you notice page load times start to increase. Your phone is ringing. Users are complaining. After mere minutes of debugging (after all you&#39;re a kung fu debugger right?) you realize your ASP.NET page is &lt;em&gt;waiting for the email to send&lt;/em&gt; . &quot;What the heck is going on here? This was an Async call,&quot; you mumble under your breathe. You curse Microsoft, and write an angry blog post about it. What happened?&lt;/p&gt;
&lt;p&gt;When you set that Async=&quot;True&quot; directive on your page you told ASP.NET that you want to do page rendering asynchronously. However, what you didn&#39;t realize is that you&#39;re doing things asynchronously with regards to the use of threads, and not the serving of the page. Let me clarify. With Async=&quot;True&quot; ASP.NET &lt;em&gt;waits for all Async calls to complete before finishing page rendering&lt;/em&gt; . It&#39;s designed so you can kick off long running IO operations like calling a database, web service, writing files, and sending email, without tying up a valuable worker thread in your ASP.NET threadpool. Instead, the IO operation gets queued up down in unmanaged Windows land and IOCP magic and the shared IO threads kick in. If you truly want to fire-and-forget, and not have your Async calls affect your page load time, here&#39;s your answer.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;using (new SynchronizationContextSwitcher()){  var s = new SmtpClient();  s.SendCompleted +=      (sender2, e2) =&amp;gt;      {          //do something when the send is done.          //retry if error, etc.      };  s.SendAsync(from.Text, to.Text, &quot;&quot;, message.Text, null);}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It should be noted that in this sample code when the SendCompleted anonymous method is called, you are &lt;em&gt;no longer in the ASP.NET context&lt;/em&gt; . The SynchronizationContextSwitcher removed this context and put you in no context, so you&#39;re just free ballin&#39;. This is important. You can&#39;t mess with the Request, Page, Response, etc. We&#39;re talking serious multi-threading now. In fact it&#39;s even likely that delegate will be executing at the same time as some other method in your page&#39;s lifecycle, on a whole other thread. So, pass anything you want to use from the page via the last parameter on the SendAsync call, pull it out of the EventArgs in your SendCompleted handler, and don&#39;t touch that page object or anything in it.&lt;/p&gt;
&lt;p&gt;I must confess. I didn&#39;t write this SynchronizationContextSwitcher class. It was another developer on our team (Boris) and then was improved by a random good Samaritan named &lt;a href=&quot;http://haacked.com/archive/2009/01/09/asynchronous-fire-and-forget-with-lambdas.aspx#70428&quot;&gt;Richard&lt;/a&gt;. It&#39;s also based on &lt;a href=&quot;http://www.codeproject.com/KB/threads/SynchronizationContext.aspx&quot;&gt;this one&lt;/a&gt; that&#39;s quite a bit more featureful/complicated.&lt;/p&gt;
&lt;p&gt;Anyway, Simply wrap your send (or any Async) call in a using block like this and, for the scope of that block, any Async operations will happen as if you were not even in ASP.NET and didn&#39;t have a Request context to worry about. Your page will be served immediately without waiting for your Async call to complete. Of course, this does have caveats. By doing a true fire and forget there is now the potential your email won&#39;t get sent and you won&#39;t even know about it. ASP.NET could shut down your app domain 1/2 way through the send and you and the user would be none the wiser. So, care must be taken to either store these things in some other reliable place before the Async call, or (as in our case) usually whatever you&#39;re firing off isn&#39;t critical, so a few missed ones here and there won&#39;t matter.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public class SynchronizationContextSwitcher  : IDisposable{  private ExecutionContext _executionContext;  private readonly SynchronizationContext _oldContext;  private readonly SynchronizationContext _newContext;  public SynchronizationContextSwitcher()      : this(new SynchronizationContext())  {  }  public SynchronizationContextSwitcher(SynchronizationContext context)  {      _newContext = context;      _executionContext = Thread.CurrentThread.ExecutionContext;      _oldContext = SynchronizationContext.Current;      SynchronizationContext.SetSynchronizationContext(context);  }  public void Dispose()  {      if (null != _executionContext)      {          if (_executionContext != Thread.CurrentThread.ExecutionContext)              throw new InvalidOperationException(&quot;Dispose called on wrong thread.&quot;);          if (_newContext != SynchronizationContext.Current)              throw new InvalidOperationException(&quot;The SynchronizationContext has changed.&quot;);          SynchronizationContext.SetSynchronizationContext(_oldContext);          _executionContext = null;      }  }}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I whipped up a &lt;a href=&quot;https://docs.google.com/viewer?a=v&amp;pid=explorer&amp;chrome=true&amp;srcid=0B7Ew2HKAAmajN2MzNDEwMTEtZTU5Ny00NjBiLWIyODQtYTdjZjc3M2UzMTEy&amp;hl=en_US&quot;&gt;small sample project&lt;/a&gt; to demo the effects I talk about here. There are two pages. One that is async, and one that isn&#39;t. It demos the error you get if you try to use an Async method on a non-async page, and simulates a slow email server on the async page. Then you can see the fire and forget in action.&lt;/p&gt;
&lt;p&gt;Async methods are extremely useful, even if you&#39;re not using fire and forget. Most of the samples you see for doing asynchronous ASP.NET pages use the IAsyncResult and Begin*/End* methods. Those are pretty complicated, and if the Async method is available why not use it? I&#39;ve written about the benefits of async programming quite a lot. Search for &quot;async&quot; up at the top right of the page.&lt;/p&gt;
</content:encoded><category>.net</category><category>async</category></item>
<item><title>10 Reasons ASP.NET Webforms Suck</title><link>https://jdconley.com/blog/10-reasons-aspnet-webforms-suck</link><guid isPermaLink="false">tag:blogger.com,1999:blog-1741199026308686058.post-8150011986971385423</guid><pubDate>Tue, 13 Jan 2009 03:24:00 GMT</pubDate><description>I&#39;ve always been a .NET Fanboy. I&#39;ve been on the bandwagon since its inception. I&#39;ve developed quite a few shipping .NET products for the web, Windows, and Linux. I&#39;ve given…</description><content:encoded>&lt;p&gt;I&#39;ve always been a .NET Fanboy. I&#39;ve been on the bandwagon since its inception. I&#39;ve developed quite a few shipping .NET products for the web, Windows, and Linux. I&#39;ve given talks at user groups, created a consulting company, and mentored developers new to .NET. I always experiment with the latest toys and try to stay ahead of the technolgoy curve. In my most recent role at Hive7, I&#39;ve been focused on web technology. We have some pretty large scale games (millions of players) built on ASP.NET webforms and ASP.NET AJAX. It&#39;s been about 8 years since I&#39;ve written a full blown web app that wasn&#39;t in ASP.NET webforms. Sure, there&#39;s the occasional small PHP or static html site, but no &quot;real&quot; applications have been built on anything but ASP.NET. I think I&#39;ve been missing out.&lt;/p&gt;
&lt;p&gt;I&#39;m going to preface this by saying one thing. Ever try to train someone new to ASP.NET? Especially someone with any other web programming experience. It&#39;s not easy. That to me is a sign of suck, or maybe fail.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Reasons (in order of frustration)&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Other web developers assume you&#39;re inferior&lt;/p&gt;
&lt;p&gt;Let&#39;s face it, if you&#39;re coding in ASP.NET you are NOT initially considered one of the cool kids. It&#39;s automatically assumed you&#39;re a corporate lackey with no programming fu. You have to prove yourself. It sucks. Yes, this is #1. Afterall, don&#39;t you want other people to think you&#39;re cool? Or am I the only one still living in high school...?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;One form to rule us all, one form to bind us&lt;/p&gt;
&lt;p&gt;I don&#39;t think I have much to say on this, other than. Why? What was the design decision behind overloading the html form and only lettings us have one? Why? Why? Why?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Viewstate&lt;/p&gt;
&lt;p&gt;Ever accidentally generated a 1MB (simple) page by just using standard controls?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;ID insanity&lt;/p&gt;
&lt;p&gt;Mapping id&#39;s in html elements to id&#39;s in code starts out innocent enough. But, throw in nested controls (a recommended design practice) and hold on for your life. Once you get used to it everything makes sense. But try showing your dhtml/javascript guy how to use codebehind to grab a ClientID and pass that to his javascript code...&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Html abstraction&lt;/p&gt;
&lt;p&gt;I truly hate that in webforms that you don&#39;t really write html code. Browser independent rending is just a bad, horrible idea. The abstraction sounds nice on the surface, but some day it will bite you. Web developers should know how to write html code, understand the web programming model, and the cross platform implications of their code.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Postbacks everywhere&lt;/p&gt;
&lt;p&gt;Linkbuttons, and any of the controls with &#39;autopostback&#39; should be taken out on the street and shot. Posting back to the initial page as the default to perform an action is just counter intuitive. And then, how do you consume this action? An event handler? Weird.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Request lifecycle&lt;/p&gt;
&lt;p&gt;Init, Load, PreRender. WTF? Try explaining that one to your javascript guy. The fact that we need a 10 step lifecycle for things to work sends off warning bells in my head.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Getting data to the client&lt;/p&gt;
&lt;p&gt;Ok, I&#39;ve got this cool data driven web site. And now I want to do some AJAX. How do you interface your server code with your Javascript? You can pick one of 20 methods, none of which are simple, and all leave the developer scratching his head. Sometimes things magically work. Usually they don&#39;t.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Ugly URL&#39;s&lt;/p&gt;
&lt;p&gt;Ok, so this one is low on the list becuase the latest service pack added a routing engine. But hey, it&#39;s bugged me for the last 8 years. Customers want pretty url&#39;s. Webforms did not deliver without much hackery.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Codebehind&lt;/p&gt;
&lt;p&gt;I love c#. But, the concept of codebehind just seems weird. Why is there a separate file that&#39;s coupled to the html code? This nifty abstraction has been the cause of so many developer questions and Visual Studio environment issues I don&#39;t even want to go there.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The odd feeling that you have to beat the framework into submission to get it to do what you want&lt;/p&gt;
&lt;p&gt;Ok, this is #11, I know. But hey, something just &lt;em&gt;feels&lt;/em&gt; wrong in webforms. Like you&#39;re trying to stick a square peg through a round hole.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;As I look over this list I realized that most things I hate about ASP.NET Webforms related to the choices that were made about abstractions. I don&#39;t understand what was so scary about the web programming model that these decisions were made. In fact, now that I think about it, I&#39;d have been happier sticking with the classic ASP programming model than using webforms. Oh well. The last 8 years will now be known as &quot;the time in my life when I had to code on that ASP.NET webforms junk&quot;. Ok I&#39;m done complaining for now. Posts in the forseeable future will be about happy things like ASP.NET MVC, Azure, and jQuery.&lt;/p&gt;
&lt;p&gt;Most recently I&#39;ve been working with the ASP.NET MVC framework and I have to say, wow. What a relief. It reminds me of doing web programming when I actually wrote simple Html code for my first web site. It&#39;s not really the MVC pattern per-se that attracts me. The joy comes from not being coupled to the desires of the ASP.NET framework developers whims. I can write javascript, html, and css. I can write server side code. And guess what, it&#39;s not necessarily coupled! Maybe in 8 years I&#39;ll be singing a different tune. But for now, I&#39;m happy again.&lt;/p&gt;
&lt;p&gt;Edit: I posted a &lt;a href=&quot;https://jdconley.com/blog/aspnet-mvc-sucks-and-so-does-jquery-and&quot;&gt;follow up&lt;/a&gt;.&lt;/p&gt;
</content:encoded><category>.net</category><category>asp.net</category></item>
<item><title>Debugging after a power outage</title><link>https://jdconley.com/blog/debugging-after-power-outage</link><guid isPermaLink="false">tag:blogger.com,1999:blog-1741199026308686058.post-4184339582627726952</guid><pubDate>Thu, 25 Sep 2008 01:18:00 GMT</pubDate><description>Here at Hive7 we host all our servers with a hybrid co-location/hosting provider. When you host your servers in a colo facility there are a few key things you look for. Stuff…</description><content:encoded>&lt;p&gt;Here at &lt;a href=&quot;http://www.hive7.com/&quot;&gt;Hive7&lt;/a&gt; we host all our servers with a hybrid co-location/hosting provider. When you host your servers in a colo facility there are a few key things you look for. Stuff like multiple redundant internet routes, clean power, zero interruption backup power systems, adequate cooling, and decent security. While our host has all of these, after all they come standard in any decent co-location, they also provide us with a few services above and beyond a bare bones colo like good prices on rented servers of any configuration and hardware load balancers. We&#39;ve had our share of small mishaps, but things have been pretty smooth sailing. That is, until, about 36 hours ago.&lt;/p&gt;
&lt;p&gt;Sometime around 5am PDT PG&amp;amp;E had a major power outage. Normally when this (rarely) happens in a colo, the backup batteries and generator carry you through without even a hiccup. Well, not this time. Backup power systems faltered and servers went down. Things quickly came back up, but, there was a catch. The Air Conditioner in our data center did not! Servers rapidly began overheating. Quick to react, the colo&#39;s on site engineers hard powered off a bunch of our servers (I&#39;m still not quite sure why we didn&#39;t get a phone call to do this on our own the safe way).&lt;/p&gt;
&lt;p&gt;Text messages flew (&lt;a href=&quot;http://www.zenoss.com/&quot;&gt;Zenoss&lt;/a&gt; is your friend) and our chief sys admin dude rushed down to the data center to assess the damages as soon as he was alerted. On the surface there were a few major issues. Many of our larger RAID Arrays were running degraded and needed some love. Some servers had not powered back on and were stuck. He spent all day trying to right the wrongs made by our colo&#39;s (lack of) backup power.&lt;/p&gt;
&lt;p&gt;While he was doing that, guess what I was doing? Yeah, trying to make &lt;a href=&quot;http://apps.facebook.com/knighthood&quot;&gt;Knighthood&lt;/a&gt; run. Knighthood is a pretty big web app. We have millions of users, and roughly 10,000 actively playing at any given point in time. With a few database servers running with degraded arrays, virtual machine hosts not running, and some other systems still not powered on I set forth scouring logs and troubleshooting. One by one we got the necessary systems back up and running. First it was the email service, then the email invitation service, then the Active Directory domain controllers. With all of these up and running properly, the game was still performing poorly. It was exhibiting performance traits I&#39;d seen before. It&#39;d go fast for a bit, then completely hang, then go fast again.&lt;/p&gt;
&lt;p&gt;In the past, a performance pattern like this has been caused by some reader/writer lock contention where an upgrade to a write lock causes everything to stop. It&#39;s also been caused by transactions hanging in Distributed Transaction Coordinator, or SQL Blocking, or contention on a big cache item in Memcached, or some code that is infinitely recursing. So, I did my normal troubleshooting in this scenario.&lt;/p&gt;
&lt;p&gt;I popped open perfmon to look at request rates, bandwidth, cpu, threads, memory, etc across the farm. Every single front end IIS server (7 of them for this game) was processing absolutely nothing for a 20 second period. And by nothing, I mean nothing. IIS wouldn&#39;t even serve up an image! And CPU was 0% utilized. But, once that 20 seconds was over we&#39;d get a good 5 seconds of processing done. Everything was queued and no requests were dropped. I thought for sure the power outage had severely damaged one of our databases, DNS servers, or a big chunk of cache (we run about 60GB of memcached), or something else obvious like that. It really &lt;em&gt;felt&lt;/em&gt; like something was timing out and then letting the flood gates open.&lt;/p&gt;
&lt;p&gt;At this point the logs weren&#39;t showing any errors to lead me down a debugging path. Since the behavior was happening consistently I decided to grab a &lt;a href=&quot;http://blogs.msdn.com/tess/archive/2006/10/16/net-hang-debugging-walkthrough.aspx&quot;&gt;hang dump&lt;/a&gt; of the w3wp process. The dump was, well, completely surprising! Guess what was happening?&lt;/p&gt;
&lt;p&gt;No really. Guess.&lt;/p&gt;
&lt;p&gt;Give Up? &lt;strong&gt;Nothing!&lt;/strong&gt; Yeah, nothing. During that 20 seconds all the managed and unmanaged threads were completely idle doing absolutely nothing. No locks were held. No pages were processing. I know that because of Tess&#39;s neat blog post about which &lt;a href=&quot;http://blogs.msdn.com/tess/archive/2005/12/20/505862.aspx&quot;&gt;threads you can ignore&lt;/a&gt;. It&#39;s as if IIS just decided we didn&#39;t really want to process any more requests. This had me scratching my head. I repeated the process another 4 or 5 times with the same result. It seemed the problem must be somewhere in kernel space. None of my user mode dumps found anything at all. That scared me.&lt;/p&gt;
&lt;p&gt;I have no experience doing kernel debugging. So, well, this is where I partially threw in the towel. I called Microsoft support and opened a premier support case. It had been about 8 hours and we had a LOT of pissed off paying users. After a few hours on the phone we captured some more user mode dumps (they didn&#39;t believe me that there wasn&#39;t anything interesting there) and uploaded them. I wish saying &quot;I am experienced doing production crash dump debugging&quot; meant something to these guys... I&#39;m not sure how many times I had to say &quot;No, you see, when it hangs it uses 0% CPU!&quot;.&lt;/p&gt;
&lt;p&gt;The Microsoft crash dump engineers went about their business and said they&#39;d call me back when they found something (though I knew they wouldn&#39;t find anything and no amount of whining could make them skip this step). To their credit, since it was production and affecting our main line of business, they offered to do the debugging immediately rather than withing 2 business days which is the normal turnaround.&lt;/p&gt;
&lt;p&gt;A couple hours later everything magically started working perfectly. I changed nothing. I called our sysadmin and he said he changed nothing that should have affected Knighthood. It had already been a long day and we decided to wait for the next day to find what had fixed it. Sysadmin dude sends me an IM this morning to let me know he figured out the problem. Guess what it was?&lt;/p&gt;
&lt;p&gt;No really. Guess.&lt;/p&gt;
&lt;p&gt;Well of course, it was IIS logging! We have all our IIS logs pointed at a NAS. I never thought this would be an issue since, well, logging happens in a background thread right? It can&#39;t possibly interfere with actual request processing. Turns out that is incorrect! The NAS was one of the last things that Sysadmin dude had brought up at the end of the day because it was only used for archiving and log files, a very low priority in a crisis scenario. Well, apparently not!&lt;/p&gt;
&lt;p&gt;Microsoft called me back about an hour later to let me know that the hang dumps did not uncover anything and it appeared that requests were simply being delayed before they could be processed. &quot;Well, no $@*! I told you that 12 hours ago&quot;, I thought. So, I let them know we had fixed the problem and closed the case. I&#39;m sure we could have seen it in a kernel hang dump in the IIS kernel mode stuff, but the problem was not reproducing anymore and I didn&#39;t want to bother...&lt;/p&gt;
&lt;p&gt;Now you know. IIS logging can clog up all your requests. So, if you&#39;re logging to a remote system over a windows share, make sure it never goes down! Or, well, don&#39;t do that and log locally and ship them out on occasion.&lt;/p&gt;
</content:encoded><category>asp.net</category><category>windows</category></item>
<item><title>ASP.NET - It&#39;s not just for DataGrids after all</title><link>https://jdconley.com/blog/aspnet-its-not-just-for-datagrids-after</link><guid isPermaLink="false">tag:blogger.com,1999:blog-1741199026308686058.post-2413166326787052170</guid><pubDate>Thu, 17 Jul 2008 17:33:00 GMT</pubDate><description>Last night I gave a talk at the San Francisco chapter of the Bay.NET User&#39;s group. It was a lot of fun. Thanks for the great interaction everyone! I am also thoroughly…</description><content:encoded>&lt;p&gt;Last night I gave a &lt;a href=&quot;http://www.baynetug.org/DesktopModules/DetailXEvents.aspx?ItemID=327&amp;mid=49&quot;&gt;talk&lt;/a&gt; at the San Francisco chapter of the Bay.NET User&#39;s group. It was a lot of fun. Thanks for the great interaction everyone! I am also thoroughly impressed that I finished nearly on time and didn&#39;t have 10 slides left! Usually I have way too much material for these things.&lt;/p&gt;
&lt;p&gt;As promised, here are &lt;a href=&quot;https://docs.google.com/viewer?a=v&amp;pid=explorer&amp;chrome=true&amp;srcid=0B7Ew2HKAAmajOTVhNTU3ZjItYjYyYi00MTE0LWIwYTEtYzI1NWIxZjAxZWM4&amp;hl=en_US&quot;&gt;the slides&lt;/a&gt; from the talk.&lt;/p&gt;
&lt;p&gt;If any other groups out there are interested in this talk, let me know!&lt;/p&gt;
</content:encoded><category>.net</category><category>asp.net</category><category>async</category><category>linq</category></item>
<item><title>Windows Server 2008</title><link>https://jdconley.com/blog/windows-server-2008</link><guid isPermaLink="false">tag:blogger.com,1999:blog-1741199026308686058.post-6930063535698047898</guid><pubDate>Sat, 24 May 2008 17:26:00 GMT</pubDate><description>For anybody who&#39;s been watching you will have noticed that I have had some fun trying to get x64 Windows Vista stable on my workstation. Well, because of all that fun I&#39;ve been…</description><content:encoded>&lt;p&gt;For anybody who&#39;s been watching you will have noticed that I have had &lt;a href=&quot;https://jdconley.com/blog/fun-installing-vista-beta-2-on-amd-x64&quot;&gt;some&lt;/a&gt; &lt;a href=&quot;https://jdconley.com/blog/vista-rant&quot;&gt;fun&lt;/a&gt; trying to get x64 Windows Vista stable on my workstation. Well, because of all that fun I&#39;ve been running good ole trusty XP Pro 32 bit (and Ubuntu) for the last 8 months or so. I noticed both Server 2008 and Vista SP1 came out and I thought, &quot;hey, it&#39;s time for an upgrade!&quot;&lt;/p&gt;
&lt;p&gt;After my last &lt;a href=&quot;https://jdconley.com/blog/vista-rant&quot;&gt;episode&lt;/a&gt; installing Vista x64 on my workstation, I decided I should instead go for Windows Server 2008 x64 – I know, it shouldn&#39;t really make a difference, but it made me feel better! So I login to MSDN, download it, burn it to disc, and away I go. Before I know it, everything is installed and working. It&#39;s been over a week now and it&#39;s still working. Not a single crash! Amazing... It&#39;s almost like, dare I say it, I got a Mac crossed with Open BSD and a touch of Linux! ;)&lt;/p&gt;
&lt;p&gt;I have to say, they did something right with Windows Server 2008 for us hardcore workstation users. It is the perfect blend of security, cutomizability, and sexiness. You gotta love a server operating system with all the IIS 7 goodness that lets you turn on Aero. :) Both of my printers even have drivers now!&lt;/p&gt;
&lt;p&gt;However, I must confess, I did cheat a little bit. I disabled my on-board sound card that was the culprit for many of my BSOD&#39;s with the prior attempts at Vista x64 and bought a PCI sound card. Ah well, Server 2008 rules, Vista sucks! There. I said It.&lt;/p&gt;
&lt;p&gt;Oh yeah, I did have one issue. For some stupid reason it didn&#39;t want to activate, giving me the stupid error:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Windows Activation Error: A problem occurred when Windows tried to activate. Error Code 0x8007232B. For a possible resolution, click More Information. Contact your system administrator or technical support department for assistance. DNS name does not exist.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Luckily there are about a million hits on Google on the subject. Here&#39;s the &lt;a href=&quot;http://www.chapterzero.co.uk/articles/fix-vista-activation-dns-error-0x8007232b.aspx&quot;&gt;most concise one.&lt;/a&gt; Yeah, you read that right, enter the same exact product key and click activate again. You would think that&#39;s an error that would have been fixed in over a year...&lt;/p&gt;
</content:encoded><category>random</category><category>windows</category></item>
<item><title>A SQL Table Manhunt</title><link>https://jdconley.com/blog/sql-table-manhunt</link><guid isPermaLink="false">tag:blogger.com,1999:blog-1741199026308686058.post-6275555993787182064</guid><pubDate>Wed, 19 Mar 2008 21:54:00 GMT</pubDate><description>As I mentioned in my last post I recently took on the exciting new position of Chief Software Architect at Hive7, Inc. We&#39;re building all kinds of great stuff. Our most popular…</description><content:encoded>&lt;p&gt;As I mentioned in my last post I recently took on the exciting new position of Chief Software Architect at &lt;a href=&quot;http://www.hive7.com/&quot;&gt;Hive7, Inc.&lt;/a&gt; We&#39;re building all kinds of great stuff. Our most popular game &lt;a href=&quot;http://apps.facebook.com/knighthood&quot;&gt;Knighthood&lt;/a&gt; has over a million registered users and over 100,000 daily actives. This game is growing quickly. Over 125,000 people added the game two weeks ago, and over 150,000 added it in the last week. The game came into existence in December.&lt;/p&gt;
&lt;p&gt;This massive growth leads to some exciting scalability challenges. I&#39;ll be spending a lot of time talking about that in the future. Today, is a simple tidbit related to databases. Our current performance bottleneck is with database write I/O. We have enough memory in the systems and a caching layer, so the disks barely need to read. Tracking this down is a whole other post, but it&#39;s fairly simple. Once we knew we were write I/O limited we set out to find out why.&lt;/p&gt;
&lt;p&gt;The original DB physical layout started out pretty simple. There was one File for data, one for logs. In the next 3 or 4 revisions more and more files were created. Why? Well, so we could run this nifty little query and find out &lt;em&gt;which&lt;/em&gt; of our db tables/indexes/etc were causing the write bottlenecks:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;select  db.name as DbName,  f.name as FileName,  f.physical_name as FilePhysicalName,  vf.TimeStamp,  vf.NumberReads,  vf.BytesRead,  vf.IoStallReadMS,  vf.NumberWrites,  vf.BytesWritten,  vf.IoStallWriteMS,  vf.BytesOnDiskfrom fn_virtualfilestats(-1,-1) vf  inner join sys.databases db on db.database_id = vf.DbId  inner join sys.database_files f on f.file_id = vf.FileIdorder by vf.NumberWrites desc
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you have physically separated your various database tables and indexes into different files, the output from this function will give you all kinds of useful information about which ones are most accessed, and which put the most strain on your I/O subsystem. Optimizing it, of course, is up to you. :)&lt;/p&gt;
&lt;p&gt;If you enjoy big scale, fast moving, tough problems, we&#39;re hiring for a &lt;a href=&quot;http://www.linkedin.com/jobs?viewJob=&amp;jobId=493724&amp;fromSearch=0&amp;sik=1205963575638&quot;&gt;Lead Web Designer&lt;/a&gt; and &lt;a href=&quot;http://www.linkedin.com/jobs?viewJob=&amp;jobId=493713&amp;fromSearch=1&amp;sik=1205963575638&quot;&gt;Brilliant Lead DBA/Sysadmin&lt;/a&gt; and &lt;a href=&quot;http://www.linkedin.com/jobs?viewJob=&amp;jobId=493706&amp;fromSearch=2&amp;sik=1205963575638&quot;&gt;Web Games Developer (.NET)!&lt;/a&gt;&lt;/p&gt;
</content:encoded><category>sql</category><category>tuning</category></item>
<item><title>C# 3.0 Overview</title><link>https://jdconley.com/blog/c-30-overview</link><guid isPermaLink="false">tag:blogger.com,1999:blog-1741199026308686058.post-9168415833215846898</guid><pubDate>Thu, 28 Feb 2008 18:14:00 GMT</pubDate><description>It&#39;s been forever since my last post. I promise I&#39;ll do better. I&#39;ve just been juggling three jobs. ;) But that has changed (more on that soon)!The last couple of nights I did…</description><content:encoded>&lt;p&gt;It&#39;s been forever since my last post. I promise I&#39;ll do better. I&#39;ve just been juggling three jobs. ;) But that has changed (more on that soon)!&lt;/p&gt;
&lt;p&gt;The last couple of nights I did the same talk at two different user groups. &lt;a href=&quot;http://www.sacnetug.org/&quot;&gt;Sacramento .NET User&#39;s Group&lt;/a&gt; and the &lt;a href=&quot;http://www.centralcaldotnet.com/&quot;&gt;Central California .NET User&#39;s Group&lt;/a&gt;. Thank you guys for having me, and not throwing any tomatoes. I think we had a good time at both events. Though, I did take up the whole two hours both times.&lt;/p&gt;
&lt;p&gt;The talk was based on &lt;a href=&quot;http://www.yoda.arachsys.com/csharp/&quot;&gt;Jon Skeet&#39;s&lt;/a&gt; upcoming book titled &lt;a href=&quot;http://www.manning.com/skeet&quot;&gt;C# in Depth&lt;/a&gt; which I had the pleasure of reviewing and providing technical feedback. We went through the evolution of C# from 1.0 to 3.0, explored a bunch of the new features, played &lt;a href=&quot;https://msmvps.com/blogs/jon.skeet/archive/2008/02/14/human-linq.aspx&quot;&gt;Human LINQ&lt;/a&gt; (hilarious). Oh yeah, it was pointed out to me in the Sacramento group that the word &quot;jumped&quot; should really be &quot;jumps&quot;. That&#39;s what I get for copying my work! hah! If anybody in the Sacramento area wants to help, I&#39;d like to do it again and video tape it...&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Stuff to Download&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.google.com/viewer?a=v&amp;pid=explorer&amp;chrome=true&amp;srcid=0B7Ew2HKAAmajYWJmYzFjOWEtNThhYy00YzdkLThiZWMtMzVlODBiNGY1MGM1&amp;hl=en_US&quot;&gt;C# 3.0 Overview Presentation&lt;/a&gt; – In both talks I didn&#39;t have enough time to bore you guys with the &quot;in depth&quot; slides. Pick up Jon&#39;s book to learn the nitty gritty about how all that stuff works.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.google.com/viewer?a=v&amp;pid=explorer&amp;chrome=true&amp;srcid=0B7Ew2HKAAmajMmYwYjgzOTMtZDhjMy00Yzg5LWFmZTYtOTg3M2Q2ZTU3Njk3&amp;hl=en_US&quot;&gt;A Sorted Affair 2&lt;/a&gt; – - A few weeks ago I published the first version of this on my blog. This one is much cooler.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.google.com/viewer?a=v&amp;pid=explorer&amp;chrome=true&amp;srcid=0B7Ew2HKAAmajNmMyODc4ZmMtNzUzZC00ZTgzLThhYzUtMjlhOGQzMTYyOGQ4&amp;hl=en_US&quot;&gt;Human LINQ&lt;/a&gt; – The code we executed with our Human LINQ provider.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.google.com/viewer?a=v&amp;pid=explorer&amp;chrome=true&amp;srcid=0B7Ew2HKAAmajZTc4Mjg3ZTYtZGFlNy00MTgwLWJhNjEtODlhYjA3YWFlYjZj&amp;hl=en_US&quot;&gt;Sort Performance&lt;/a&gt; – A quick exploration of the relative sorting speeds using different sort methods.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I&#39;ll write up another quick blog in a bit on the sort performance. It&#39;s quite interesting, indeed.&lt;/p&gt;
</content:encoded><category>.net</category><category>linq</category><category>random</category></item>
<item><title>A New Kind of Application Server</title><link>https://jdconley.com/blog/new-kind-of-application-server</link><guid isPermaLink="false">tag:blogger.com,1999:blog-1741199026308686058.post-8579264127606836594</guid><pubDate>Mon, 04 Feb 2008 17:52:00 GMT</pubDate><description>As you probably know, I&#39;m a cofounder of Coversant which, at its heart, is an XMPP development platform. Most of our larger customers (thousands of simultaneous users) are…</description><content:encoded>&lt;p&gt;As you probably know, I&#39;m a cofounder of &lt;a href=&quot;http://www.coversant.com/&quot;&gt;Coversant&lt;/a&gt; which, at its heart, is an XMPP development platform. Most of our larger customers (thousands of simultaneous users) are ISV&#39;s that have built on the SoapBox Platform®. We allow you to easily develop XMPP applications using .NET technology.&lt;/p&gt;
&lt;p&gt;A really long time ago, I wrote about some &lt;a href=&quot;https://jdconley.com/blog/soapbox-platform-possibilities&quot;&gt;possibilities for using the SoapBox Platform&lt;/a&gt; including examples of what our customers were doing at the time. This was before there microblogging was popular, or I probably would have used that example too. :)&lt;/p&gt;
&lt;p&gt;The last couple of weeks there seems to be quite a bit of buzz around the subject of using XMPP as an application server, and that gets me really excited! A friend/competitor Matt Tucker of Jive Software wrote in his company blog about how &lt;a href=&quot;http://www.jivesoftware.com/community/blogs/jivetalks/2008/01/24/xmpp-aka-jabber-is-the-future-for-cloud-services&quot;&gt;XMPP is the future for cloud services&lt;/a&gt;. A &quot;real&quot; online author (aka not a member of an XMPP company) even &lt;a href=&quot;http://www.readwriteweb.com/archives/xmpp_web.php&quot;&gt;picked up Matt&#39;s article&lt;/a&gt; and ran with it. Yesterday, a little buzz &lt;a href=&quot;http://developers.slashdot.org/article.pl?sid=08/02/04/1320210&quot;&gt;hit Slashdot&lt;/a&gt; when another friend/competitor Mickael Raymond of Process One wrote about &lt;a href=&quot;http://www.process-one.net/en/blogs/article/introducing_the_xmpp_application_server/&quot;&gt;introducing the XMPP application server&lt;/a&gt; (when I wrote this, it seems Process One was experiencing a bit of the Slashdot effect -- hopefully by the time you read this it will be gone and you can read his article), which is an exploration of building a Twitter-like microblogging system on top of their XMPP server. Great stuff, indeed!&lt;/p&gt;
&lt;p&gt;This is wonderful news and very validating for me personally! It seems after six years of committing to the infant technology, I wasn&#39;t crazy after all, and XMPP is a good platform for presence/messaging systems! And if you&#39;re in the market for .NET based XMPP solutions, head on over to the &lt;a href=&quot;http://developers.coversant.com/&quot;&gt;SoapBox Developer site&lt;/a&gt;. :)&lt;/p&gt;
</content:encoded><category>.net</category><category>soapbox</category><category>xmpp</category></item>
<item><title>A Sorted Affair: History of the C# Sort</title><link>https://jdconley.com/blog/sorted-affair-history-of-c-sort</link><guid isPermaLink="false">tag:blogger.com,1999:blog-1741199026308686058.post-4735818999066519398</guid><pubDate>Thu, 31 Jan 2008 07:43:00 GMT</pubDate><description>Next month I&#39;ll be giving a talk at the Sacramento .NET User&#39;s group titled C# 3.0 Overview where I&#39;ll be presenting the great new features in the third version of C#. I&#39;ve…</description><content:encoded>&lt;p&gt;Next month I&#39;ll be giving a talk at the Sacramento .NET User&#39;s group titled &lt;a href=&quot;http://www.sacnetug.org/sacnet/speakers16.htm#JDConley&quot;&gt;C# 3.0 Overview&lt;/a&gt; where I&#39;ll be presenting the great new features in the third version of C#. I&#39;ve been developing .NET/C# software since the first pre-release copies of Visual Studio .NET reached MSDN. It&#39;s been fun to see the fledgling C# language evolve with the times. In just a few short years it&#39;s gone from what many considered to be an uninspired Java clone to a highly productive, unique, language.&lt;/p&gt;
&lt;p&gt;Today I&#39;m going to spoil the opener code sample to my user group presentation. Let&#39;s take a journey through the life of C# as a developer with a simple task: sorting a list! I even made a super &lt;a href=&quot;http://en.wikipedia.org/wiki/Leet&quot;&gt;1337&lt;/a&gt; &lt;a href=&quot;https://docs.google.com/viewer?a=v&amp;pid=explorer&amp;chrome=true&amp;srcid=0B7Ew2HKAAmajMTY2MjkxMTYtMDE0My00OTkxLTgzMDItMjZmMmY5MDRjMjY0&amp;hl=en_US&quot;&gt;Winforms app&lt;/a&gt; you can play with.&lt;/p&gt;
&lt;p&gt;&lt;a id=&quot;BLOGGER_PHOTO_ID_5632512635503791154&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://jdconley.com/blog-assets/imported/677e7b141e81e737955a7d30.png&quot;&gt;&lt;img src=&quot;https://jdconley.com/blog-assets/imported/677e7b141e81e737955a7d30.png&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;For the purposes of this example, we&#39;re going to use a simple class called Person. We&#39;ll be sorting the list by the person&#39;s first name.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public class Person{  public string FirstName { get; set; }  public string LastName { get; set; }  public override string ToString()  {      return FirstName + &quot; &quot; + LastName;  }  public override int GetHashCode()  {      return FirstName.GetHashCode() ^ LastName.GetHashCode();  }  public static ICollection&amp;lt;Person&amp;gt; GetPeople()  {      return new List&amp;lt;Person&amp;gt;      {          new Person{FirstName=&quot;Ray&quot;,LastName=&quot;Ozzie&quot;},          new Person{FirstName=&quot;Larry&quot;,LastName=&quot;Ellison&quot;},          new Person{FirstName=&quot;Steve&quot;,LastName=&quot;Jobs&quot;},          new Person{FirstName=&quot;Bill&quot;,LastName=&quot;Gates&quot;},          new Person{FirstName=&quot;Britney&quot;,LastName=&quot;Spears&quot;}      };  }}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;C# 1.0&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In the beginning, there was C# 1.0. C++, VB, and COM be damned! For the majority of Microsoft based development, this new environment was a godsend. We enjoyed the benefits of a garbage collected, managed runtime, with the speed of native code. Life was good, but more than a bit clunky.&lt;/p&gt;
&lt;p&gt;For the prim and proper developer out there, the ArrayList just didn&#39;t cut it. We used CollectionBase and implemented our own strongly typed collections. Here&#39;s my collection, in all its glory!&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public class PersonCollection  : CollectionBase{  public PersonCollection()  {  }  public PersonCollection(IEnumerable people)  {      foreach (Person p in people)          base.InnerList.Add(p);  }  public int Add(Person p)  {      return base.InnerList.Add(p);  }  public void Remove(Person p)  {      base.InnerList.Remove(p);  }  public Person this[int index]  {      get      {          return (Person)base.InnerList[index];      }      set      {          base.InnerList[index] = value;      }  }  public void Sort()  {      base.InnerList.Sort();  }  public void Sort(IComparer comparer)  {      base.InnerList.Sort(comparer);  }  public void Sort(int index, int count, IComparer comparer)  {      base.InnerList.Sort(index, count, comparer);  }}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ok, we&#39;ve got a collection of people. Now, we can finally sort them, C# 1.0 style! There&#39;s a class called Sorting in the download that these methods are a part of.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public PersonCollection SortCS1(PersonCollection people){  PersonCollection sortedList = new PersonCollection();  foreach (Person p in people)      sortedList.Add(p);  sortedList.Sort(new PersonFirstNameComparer());  return sortedList;}private class PersonFirstNameComparer : IComparer{  public int Compare(object x, object y)  {      return ((Person)x).FirstName.CompareTo(((Person)y).FirstName);  }}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Goodness, that&#39;s a lot of code! No wonder we didn&#39;t sort anything in C# 1.0. Not only do you have to create a custom collection class, there is also a custom Comparer class! And there&#39;s no getting around this when you want to sort by a member of a complex business object.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;C# 2.0&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;C# 2.0 came along with the .NET Framework 2.0 and a host of improvements. Features like generics, anonymous methods, custom iterators, and partial classes changed the face of the language for the better. No longer did we have to spend time writing the same code like Collection classes over and over, and could focus more on getting things done.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public IEnumerable&amp;lt;Person&amp;gt; SortCS2(IEnumerable&amp;lt;Person&amp;gt; people){  List&amp;lt;Person&amp;gt; sortedList = new List&amp;lt;Person&amp;gt;(people);  sortedList.Sort(delegate(Person x, Person y) { return x.FirstName.CompareTo(y.FirstName); });  return sortedList;}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Wow, so compared to C# 1.0&#39;s 60+ lines of code, in 2.0 we wrote one. Very nice. Though, that anonymous method syntax still really bugs me. It&#39;s ugly! Why should I have create a full method signature just to do a simple one line function. Ah yes...&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;C# 3.0&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Enter C# 3.0. This is by far the biggest leap forward in C# to date. With the inclusion of lambda expressions we&#39;re now able to do some real functional programming, without the anonymous method gunk to get in the way. Check out the list sorting now!&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public IEnumerable&amp;lt;Person&amp;gt; SortCS3(IEnumerable&amp;lt;Person&amp;gt; people){  return people.OrderBy(p =&amp;gt; p.FirstName);}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Doesn&#39;t that look so much better than the 2.0 version? And it&#39;s &lt;em&gt;light years&lt;/em&gt; better than the 1.0 version. Clear, concise code. It isn&#39;t cluttered up with extra, unnecessary syntax. It&#39;s just business. The way it should be.&lt;/p&gt;
&lt;p&gt;Since 3.0 also comes with the LINQ syntax, I thought I&#39;d throw that example in there as well.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public IEnumerable&amp;lt;Person&amp;gt; SortCS3Linq(IEnumerable&amp;lt;Person&amp;gt; people){  return from p in people orderby p.FirstName select p;}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I admit, in this casee the LINQ syntax weighs you down, but you can&#39;t say it&#39;s not clear what&#39;s going on. Throw some cross joins and advanced filters in there and it will start to look at lot more appealing.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The End&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;C# has changed quite a bit over the last six years, and I can&#39;t say I disklike any of it.&lt;/p&gt;
</content:encoded><category>.net</category><category>linq</category></item>
<item><title>Unadulterated Expurgation!</title><link>https://jdconley.com/blog/unadulterated-expurgation</link><guid isPermaLink="false">tag:blogger.com,1999:blog-1741199026308686058.post-3585706395835555227</guid><pubDate>Fri, 14 Dec 2007 16:34:00 GMT</pubDate><description>Alright, so, occasionally I post something funny that happened recently. Yesterday I received a spam company broadcast email from an anonymous customer of mine. You know who…</description><content:encoded>&lt;p&gt;Alright, so, occasionally I post &lt;a href=&quot;https://jdconley.com/blog/geeks-with-kids&quot;&gt;something funny&lt;/a&gt; that happened recently. Yesterday I received a &lt;s&gt;spam&lt;/s&gt; company broadcast email from an anonymous customer of mine. You know who you are! :)&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Team Anonymous Company,&lt;/p&gt;
&lt;p&gt;In each office Anonymous Company employees have inhabited, many attempts have been made to keep our refrigerators clean and sanitary. Keeping clean refrigerators only works if we all participate – yet despite the best team players on the planet, we’ve fallen short of the goal. Common comments run the gamut from, &quot;I’ll never put &#39;my&#39; lunch in there,&quot; to the more lyrical, &quot;There’s a fungus among us!&quot;&lt;/p&gt;
&lt;p&gt;As a result of this circumstance, the many must suffer the failings of a few – meaning:&lt;/p&gt;
&lt;p&gt;Every Friday afternoon at 4:00 p.m. our Sergeant of Sanitation, will remove and dispose of everything from every refrigerator – as in: any one thing, each thing, the sum of all things, collectively all, the aggregate of all, anything at all, the totality of all within, including or comprehending all things, a comprehensive sweep of any and all things, whatever it is, whatever is left, nothing will be left, the sum total of all things, the Full Monty, the whole enchilada (frozen and unfrozen), the whole shebang. In short, every Friday at 4:00 p.m. all the refrigerators will experience an unadulterated expurgation!&lt;/p&gt;
&lt;p&gt;Many thanks in advance for your cooperation and understanding,&lt;/p&gt;
&lt;p&gt;The Management&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Good thing I don&#39;t use the fridge...&lt;/p&gt;
</content:encoded><category>random</category></item>
<item><title>Introduction to fbasync: an Asynchronous Facebook Library (Part 1)</title><link>https://jdconley.com/blog/introduction-to-fbasync-asynchronous</link><guid isPermaLink="false">tag:blogger.com,1999:blog-1741199026308686058.post-8830681557683240270</guid><pubDate>Wed, 12 Dec 2007 06:06:00 GMT</pubDate><description>I&#39;d like to start off by saying asynchronous programming is easy. Building asynchronous frameworks is hard, but using them is easy. Everybody doing programming in AJAX and…</description><content:encoded>&lt;p&gt;I&#39;d like to start off by saying asynchronous programming is easy. Building asynchronous frameworks is hard, but using them is easy. Everybody doing programming in AJAX and Flash do it every day without thinking about it. There&#39;s no reason us C# .NET programmers can&#39;t do the same!&lt;/p&gt;
&lt;p&gt;This first article about &lt;a href=&quot;http://www.codeplex.com/fbasync&quot;&gt;fbasync&lt;/a&gt; is going to show how to use it. Your 12 year old &lt;a href=&quot;http://en.wikipedia.org/wiki/Script_kiddie&quot;&gt;script kiddie&lt;/a&gt; nephew could do it, I promise. Then later on in the series we&#39;ll dive into how the library is implemented and see if we can forever scare him away from a programming career.&lt;/p&gt;
&lt;p&gt;Those who know me well (or have read my blog for a while) know I&#39;m a proponent of asynchronous patterns. Why? Well, there are a lot of reasons. I&#39;ve mentioned why &lt;a href=&quot;https://jdconley.com/blog/how-to-build-scalable-net-server&quot;&gt;1&lt;/a&gt; &lt;a href=&quot;https://jdconley.com/blog/building-reactive-user-interfaces-in&quot;&gt;2&lt;/a&gt; &lt;a href=&quot;https://jdconley.com/blog/simpler-isnt-always-better&quot;&gt;3&lt;/a&gt; &lt;a href=&quot;https://jdconley.com/blog/asyncify-your-code&quot;&gt;4&lt;/a&gt; &lt;a href=&quot;https://jdconley.com/blog/photo-feeds-facebook-application&quot;&gt;5&lt;/a&gt; &lt;a href=&quot;https://jdconley.com/blog/async-facebook-library-teaser&quot;&gt;6&lt;/a&gt; times. To sum it up, the two primary reasons for using asynchronous patterns are to gain better vertical scalability (to do more with one piece of hardware) and provide a better user experience. When it&#39;s as easy as writing synchronous code, I say why not? Using asynchronous patterns in your code is especially important when it comes to communicating with a web service outside of your network (like Facebook). When you don&#39;t know how long your service calls are going to take, you simply can&#39;t expect to scale up an application without going asynchronous!&lt;/p&gt;
&lt;p&gt;In a previous article entitled &lt;a href=&quot;https://jdconley.com/blog/simpler-isnt-always-better&quot;&gt;Simpler Isn&#39;t Always Better&lt;/a&gt; I spent a lot of time bashing the &lt;a href=&quot;http://msdn2.microsoft.com/en-us/library/awb8dkht.aspx&quot;&gt;event based&lt;/a&gt; asynchronous pattern. Well, I take it back (some of it). It turns out in the context of ASP.NET and Winforms, the event based pattern is very nice indeed. While I implemented both the event based and &lt;a href=&quot;http://msdn2.microsoft.com/en-us/library/ms228972.aspx&quot;&gt;IAsyncResult&lt;/a&gt; pattern in fbasync, I&#39;d recommend most people use the event based interface. This is what we&#39;ll be looking at today.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What you&#39;ve been waiting for&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Ok, enough blabbering! The fbasync library is available on &lt;a href=&quot;http://www.codeplex.com/fbasync&quot;&gt;CodePlex&lt;/a&gt;. You can download the bits right now and follow along at home. The library comes with a simple example that allows you to browse the photo albums uploaded by you and your friends. In this sample we get all the albums and related cover photos of the requested user, and the list of friends for the authenticated user on the server through asynchronous requests. Let&#39;s get it setup and take a deeper look!&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Make sure you have Visual Studio 2008 installed. It&#39;s required.&lt;/li&gt;
&lt;li&gt;Download and extract the zip file somewhere interesting.&lt;/li&gt;
&lt;li&gt;Open the fbasync.sln file.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Now that you have the web site loaded just make sure your web server is setup to run on port 30912 and the virtual path is &quot;/&quot; (in your project properties). This is the way the sample application is configured in Facebook. If you have your own application (API Key/Secret) you want to test this with, edit the web.config.&lt;/p&gt;
&lt;p&gt;&lt;a id=&quot;BLOGGER_PHOTO_ID_5632506573214993058&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://jdconley.com/blog-assets/imported/6e49d1c0913759e63e9c21e6.png&quot;&gt;&lt;img src=&quot;https://jdconley.com/blog-assets/imported/6e49d1c0913759e63e9c21e6.png&quot; alt=&quot;Project Setup&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;With this setup, you&#39;ll be able to run the fbasync.web application, add it through Facebook, and experiment with it in the Facebook iframe.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Setting up your page&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Getting your Facebook application setup and working is outside the scope of this article. Check out the &lt;a href=&quot;http://developers.facebook.com/&quot;&gt;Facebook Developer&lt;/a&gt; site for introduction information. Once you decide you want a Facebook canvas page with an iframe application, return here. :)&lt;/p&gt;
&lt;p&gt;It&#39;s quite easy to get your page connected to Facebook. Simply inherit from the fbasync.webcomponents.FacebookPage. Once we hit the 1.0 release of the library, you&#39;ll also be able to drag a component onto an existing page without messing with your inheritance hierarchy. For now, here&#39;s how it looks.&lt;/p&gt;
&lt;p&gt;&lt;a id=&quot;BLOGGER_PHOTO_ID_5632507886074985138&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://jdconley.com/blog-assets/imported/00d9eb78e0709a898d8af2f6.png&quot;&gt;&lt;img src=&quot;https://jdconley.com/blog-assets/imported/00d9eb78e0709a898d8af2f6.png&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Once you&#39;ve got your page setup, using the library is simple. The base page takes care of making sure the request is authenticated and gets a Facebook session based on the authentication token provided to your application. Before we go any further, make sure you set the Async directive on your page so fbasync can do things asynchronously. How async pages work was explained well by Fritz Onion in an &lt;a href=&quot;http://msdn.microsoft.com/msdnmag/issues/06/07/ExtremeASPNET/&quot;&gt;Extreme ASP.NET article&lt;/a&gt; last year.&lt;/p&gt;
&lt;p&gt;&lt;a id=&quot;BLOGGER_PHOTO_ID_5632509177057507954&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://jdconley.com/blog-assets/imported/a328404ddc563610eb8ba0f8.png&quot;&gt;&lt;img src=&quot;https://jdconley.com/blog-assets/imported/a328404ddc563610eb8ba0f8.png&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Now that you have setup the page to process requests asynchronously, fbasync can best do its magic. Override the OnFacebookSessionCreated method in your page, or add a handler for the FacebookSessionCreated event. This will be raised when fbasync has acquired a session from Facebook, using either the authentication token provided in the Facebook iframe or after a redirect through the Facebook login page. The Facebook authentication process is covered in depth in the &lt;a href=&quot;http://developers.facebook.com/documentation.php?v=1.0&amp;doc=auth&quot;&gt;Facebook Developer Authentication Overview&lt;/a&gt;. The good news is, you probably don&#39;t need to know! Fbasync will handle the most common situation for you.&lt;/p&gt;
&lt;p&gt;Now that you&#39;ve got a Facebook session, it&#39;s time to do something interesting. Let&#39;s take a look at the code in our AlbumBrowse page.&lt;/p&gt;
&lt;p&gt;&lt;a id=&quot;BLOGGER_PHOTO_ID_5632507642583989906&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://jdconley.com/blog-assets/imported/987a8f36a88921c3ccaf6a46.png&quot;&gt;&lt;img src=&quot;https://jdconley.com/blog-assets/imported/987a8f36a88921c3ccaf6a46.png&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;There are two interesting bits in this code (they&#39;re in giant red boxes – hard to miss). First, we setup event handlers for the *Completed events we are interested in. Second, we call the *Async methods. Notice in this example we&#39;re doing three &lt;em&gt;simultaneous&lt;/em&gt; asynchronous requests. That&#39;s important. These requests will happen &lt;em&gt;simultaneously&lt;/em&gt; . That, is the power of asynchronous code in action. Imagine each call takes 250ms to complete. With three calls, that&#39;s nearly 750ms of time just waiting around for Facebook. Using the asynchronous pages we end up waiting only as long as it takes for the longest running call to complete!&lt;/p&gt;
&lt;p&gt;At this point astute readers will point out that I am in fact lying. In the default configuration of .NET, you will only ever make &lt;em&gt;two&lt;/em&gt; simultaneous calls to a given remote IP. This is built-in to the WebRequest class. Lucky for us, we can change it in the web.config like so!&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;system.net&amp;gt;   &amp;lt;connectionManagement&amp;gt;       &amp;lt;add address=&quot;*&quot; maxconnection=&quot;100&quot; /&amp;gt;   &amp;lt;/connectionManagement&amp;gt;&amp;lt;/system.net&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With this configuration entry in place we can now make up to 100 simultaneous outgoing requests to the same IP address. Much better. Even if you&#39;re not using fbasync, you should make a similar change.&lt;/p&gt;
&lt;p&gt;Back to the example. Making asynchronous requests is interesting, but requests don&#39;t usually do us much good without dealing with the results. The list of friends on the left side of the application is generated using a ListView control and some simple codebehind. I&#39;m going to leave the HTML markup out of it, as its dirt simple. Have a look at the code if interested. Here&#39;s the codebehind that renders the user list.&lt;/p&gt;
&lt;p&gt;&lt;a id=&quot;BLOGGER_PHOTO_ID_5632507494763246610&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://jdconley.com/blog-assets/imported/4a5672f537a1af6858328e99.png&quot;&gt;&lt;img src=&quot;https://jdconley.com/blog-assets/imported/4a5672f537a1af6858328e99.png&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Surprised? There are no red highlights. There&#39;s nothing very interesting here. If you haven&#39;t seen many lambda functions or LINQ before, the OrderBy and Single methods might look funny, but the code here is pretty darn simple. We remove our event handler (not doing this is prone to memory leaks so I always do it). Then we bind the ListView to the Result on the event argument. And finally we put the friends name who&#39;s albums we are viewing in the placeholder. Yup, that&#39;s it. No thread locking, no monitor, no mutex, no volatiles, no interlocks, &lt;em&gt;none&lt;/em&gt; of that scary threading stuff at all.&lt;/p&gt;
&lt;p&gt;Let&#39;s review what happened. Our page loaded. The fbasync library got a session from Facebook (or pulled one out of the cache/session – more on this in a future post). Our GetUsersAsync method was kicked off (among others). It finished, in a background thread, and raised the GetUsersCompleted event &lt;em&gt;back in the context of our ASP.NET request&lt;/em&gt; . We took the results and bound them to a list view. No muss, no fuss. No threading required. My grandmother could do it – well, if she knew ASP.NET.&lt;/p&gt;
&lt;p&gt;This is getting too long already. I&#39;m starting to feel like I&#39;m writing a &lt;a href=&quot;http://weblogs.asp.net/scottgu/&quot;&gt;Scott Guthrie&lt;/a&gt; article. Coming soon: we&#39;ll wrap up the rest of the example code, and move onto how the *Async methods are implemented. I&#39;d love to get some more contributors on this project. So, if you&#39;re interested, give me a buzz or head on over to &lt;a href=&quot;http://www.codeplex.com/fbasync&quot;&gt;CodePlex&lt;/a&gt; and get crackin! Feedback is welcome and encouraged.&lt;/p&gt;
</content:encoded><category>.net</category><category>async</category><category>facebook</category><category>fbasync</category></item>
<item><title>Geeks With Kids</title><link>https://jdconley.com/blog/geeks-with-kids</link><guid isPermaLink="false">tag:blogger.com,1999:blog-1741199026308686058.post-9056388359802407533</guid><pubDate>Fri, 07 Dec 2007 01:16:00 GMT</pubDate><description>I was just IMing with a good geek friend of mine. This is what happens when you give paranoid geeks kids (names removed for obvious reasons).(5:08:06 PM) Geek Friend: i&#39;m outta…</description><content:encoded>&lt;p&gt;I was just IMing with a good geek friend of mine. This is what happens when you give paranoid geeks kids (names removed for obvious reasons).&lt;/p&gt;
&lt;blockquote&gt;
&lt;pre&gt;&lt;code&gt;(5:08:06 PM) Geek Friend: i&#39;m outta here, i gotta go home,looks like the kids are fighting(5:08:15 PM) Geek Friend: no adult supervision(5:08:20 PM) Me: haha(5:08:26 PM) Me: you watching them on camera?(5:08:27 PM) Geek Friend: i&#39;m so glad my parents didn&#39;t havevideo cameras all over my house when i was their age(5:08:30 PM) Me: hahahha(5:08:34 PM) Geek Friend: watching, listening(5:08:39 PM) Me: and they know?(5:08:42 PM) Geek Friend: going to go ground two of them(5:08:44 PM) Geek Friend: yeah, they know(5:08:47 PM) Me: wow(5:08:56 PM) Me: and they still act up(5:08:56 PM) Me: crazy(5:09:04 PM) Geek Friend: kid0 was straight up punching kid1just now(5:09:08 PM) Geek Friend: elbowed him in the face(5:09:17 PM) Geek Friend: tried to gouge his eyes with herfingers...(5:09:17 PM) Me: nice(5:09:19 PM) Geek Friend: crazy fight(5:09:25 PM) Geek Friend: never seen them do anything likethat before(5:09:30 PM) Me: well get goin!(5:09:33 PM) Me: before one of them dies(5:09:38 PM) Geek Friend: i called them(5:09:42 PM) Me: ah(5:09:43 PM) Geek Friend: they&#39;re sitting in the cornersof the room(5:09:46 PM) Me: lol(5:09:47 PM) Geek Friend: and can&#39;t move(5:10:05 PM) Geek Friend: i turned on the alarm, i toldthem if they move, the alarm will go off and the policewill come(5:10:21 PM) Geek Friend: (not true though) just a reallyloud noise until i shut it off(5:10:49 PM) Geek Friend: later
&lt;/code&gt;&lt;/pre&gt;
&lt;/blockquote&gt;
</content:encoded><category>random</category></item>
<item><title>Async Facebook Library Teaser</title><link>https://jdconley.com/blog/async-facebook-library-teaser</link><guid isPermaLink="false">tag:blogger.com,1999:blog-1741199026308686058.post-2939929600917594074</guid><pubDate>Wed, 05 Dec 2007 17:20:00 GMT</pubDate><description>I&#39;ve been trolling the Facebook Developer Forums recently and talking with other developers. I&#39;ve also been reading a lot and trying to get a feel for what people might want…</description><content:encoded>&lt;p&gt;I&#39;ve been trolling the Facebook Developer Forums recently and talking with other developers. I&#39;ve also been reading a lot and trying to get a feel for what people might want out of the asynchronous Facebook library I&#39;ve been (slowly) building. In particular, I&#39;ve been participating in &lt;a href=&quot;http://forum.developers.facebook.com/viewtopic.php?pid=19659&quot;&gt;this thread&lt;/a&gt; about Facebook scalability issues. I thought I would share my &lt;a href=&quot;http://forum.developers.facebook.com/viewtopic.php?pid=19659#p19659&quot;&gt;most recent&lt;/a&gt; post as a bit of a teaser as what&#39;s to come. Here it is, reproduced:&lt;/p&gt;
&lt;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;tomten wrote:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;...but it was way overkill for what I&#39;ve done. ...&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is one myth I want to squash. Async stuff isn&#39;t hard. I promise. smile Let&#39;s take your page loading example, and make it asynchronous. I put in code comments for a &quot;facebook is hammered&quot; timing. Let&#39;s say every call takes you 250ms. That means that page will spend roughly one second waiting for facebook.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Page_Load { GetSession(); // Call to Facebook 250ms RenderHtml(); Response.Flush(); Response.Close(); // Make calls to Facebook GetFriends(); // Call to Facebook 250ms UpdateProfile(); // Call to Facebook 250ms SendNotification(); // Call to Facebook 250ms}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, let&#39;s make this Async. It would become (roughly -- there is also a &quot;Completed&quot; event handler you&#39;d setup for the items you cared about):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Page_Load {fbasync.GetSessionAsync();fbasync.GetFriendsAsync();fbasync.UpdateProfileAsync();fbasync.SendNotificationAsync();}Page_PreRenderCompelete {RenderHtml();Response.Flush();Response.Close();}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This time, with the async calls in the server, we spend 0 time waiting for facebook. Just like in client side AJAX, we get a callback when the calls were complete! And, instead of a full second for our page to finish processing, it only takes 250ms, as all the facebook calls happen simultaneously (yeah I know this is a faulty assumption, but it is usually pretty close).&lt;/p&gt;
&lt;p&gt;In addition to the shorter page lifecycle (250ms instead of 1 second) we are not tying up a processing thread (of which there is a small finite number). During that time we are waiting for facebook to finish our API calls, the asp.net engine happily processes more requests on the thread that originally kicked off processing of our page.&lt;/p&gt;
&lt;p&gt;A shorter lifecycle is important, not only for throughput, but also for memory consumption and garbage collection efficiency. Because the objects do not live for as long, they will be garbage collected more quickly and your application will spend less time doing garbage collection.&lt;/p&gt;
&lt;p&gt;Ok, so that&#39;s a bit of a spoiler, but, I hope it helps.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Hopefully some time this week I&#39;ll clean up the library enough that I think it&#39;s worthy to be posted publicly. I spent last night refactoring a bit and removing a lot of &quot;who wrote this crap&quot; code. :)&lt;/p&gt;
&lt;p&gt;As a bit of an aside, I was excited to see the team working on the &quot;almsot official&quot; Microsoft .NET library for Facebook released an asynchronous version of the FacebookService. I thought maybe I wouldn&#39;t have to write one myself. However, after looking at the code, I was very disappointed by the fake asynchronous support that&#39;s in the &lt;a href=&quot;http://www.codeplex.com/FacebookToolkit&quot;&gt;Facebook Developer Toolkit&lt;/a&gt;. It made me shed a tear. I really wish they&#39;d put a disclaimer up: &quot;This AsyncFacebookService is not really asynchronous I/O. It will only make things worse by tying up an additional threadpool thread waiting for the delegate to the synchronous method to return.&quot;.&lt;/p&gt;
</content:encoded><category>.net</category><category>asp.net</category><category>async</category><category>facebook</category></item>
<item><title>An Entrepreneurial Story</title><link>https://jdconley.com/blog/entrepreneurial-story</link><guid isPermaLink="false">tag:blogger.com,1999:blog-1741199026308686058.post-3522871326611177809</guid><pubDate>Fri, 30 Nov 2007 15:13:00 GMT</pubDate><description>I don&#39;t remember how exactly I got there, but while clicking through my morning feeds I ended up at the very interesting story of an Australian .NET micro ISV startup called…</description><content:encoded>&lt;p&gt;I don&#39;t remember how exactly I got there, but while clicking through my morning feeds I ended up at &lt;a href=&quot;http://blog.shuffletext.com/?p=4&quot;&gt;the very interesting story&lt;/a&gt; of an Australian .NET micro ISV startup called &lt;a href=&quot;http://www.shuffletext.com/&quot;&gt;Shuffle Text&lt;/a&gt;. They outline pretty much everything we learned when we started &lt;a href=&quot;http://www.coversant.com/&quot;&gt;Coversant&lt;/a&gt; nearly seven years ago.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Some Gems&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;And while we believed that technical differentiation would be enough to sell our product, we ended up being dead wrong.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;Change, it turned out, ended up being one of our worst development enemies.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;Of all those Google Ads signups, we got 0 feedback. All feedback on the product beta came from friends or friends of friends.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;There’s a bajillion ISV’s out there all competing to sell their crappy untested memory leaking piece of junk software. No matter how much time you spend perfecting your algorithm, improving the performance, and making sure you’ve got zero tolerance for leaks, NOBODY CARES. At the end of the day, it’s getting noticed that matters, convincing people that they should take a bet on you to solve their problems.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Don&#39;t give up guys. The product&#39;s been out less than a month and people are blogging about you! Your marketing seems pretty solid to me. While I don&#39;t have a use for your software at this very second. I&#39;ll certainly keep it on my radar. Oh yeah, consider putting out a completely free version, as in beer, &lt;em&gt;not&lt;/em&gt; a trial.&lt;/p&gt;
</content:encoded><category>business</category><category>random</category></item>
<item><title>Linq to Sql Surprise Performance Hit</title><link>https://jdconley.com/blog/linq-to-sql-surprise-performance-hit</link><guid isPermaLink="false">tag:blogger.com,1999:blog-1741199026308686058.post-1887030120170852789</guid><pubDate>Thu, 29 Nov 2007 05:13:00 GMT</pubDate><description>A couple days ago I built Photo Feeds. I wrote about it here. After using the app a bit I noticed something peculiar. The page took a really long time to load. From my local…</description><content:encoded>&lt;p&gt;A couple days ago I built &lt;a href=&quot;http://apps.facebook.com/photofeeds/&quot;&gt;Photo Feeds&lt;/a&gt;. I wrote about it &lt;a href=&quot;https://jdconley.com/blog/photo-feeds-facebook-application&quot;&gt;here&lt;/a&gt;. After using the app a bit I noticed something peculiar. The page took a really long time to load. From my local web server it was on the order of 2-5 seconds. That&#39;s &lt;em&gt;way&lt;/em&gt; too slow.&lt;/p&gt;
&lt;p&gt;Having written the code a few hours prior, I immediately knew what was wrong. I thought &quot;Well, duh, either Facebook sucks, I&#39;m hitting my database too often, or I&#39;m calling the Facebook service too often.&quot; I/O is, after all, usually what causes an application this simple to be slow. I glanced over the code and thought to myself &quot;Holy crap, who wrote this junk? It&#39;s calling the database waaaaay too much. That has to be the problem.&quot;&lt;/p&gt;
&lt;p&gt;Having been down this path many times I decided to analyze a bit more before officially jumping to conclusions. I popped open task manager to see if I was in fact I/O bound (i.e. to see if my CPU was racing or idle) – usually a good rough indicator of what&#39;s going on. To my jaw-dropped amazement the CPU was hitting 100% for the majority of the page request time. &quot;Could it be the JIT?&quot; I thought. So I hit refresh 50 times and watched in amazement as the CPU spiked each time. I switched over to the Processes tab and, again to my amazement, noticed it was the web server chewing up the cycles, and NOT SQL server. Did I mention I was amazed?&lt;/p&gt;
&lt;p&gt;Ok, so apparently I was &lt;em&gt;wrong&lt;/em&gt; [insert shock and awe]. The web site was way too CPU hungry! Good thing I didn&#39;t put any bets on that one. I then theorized that maybe Cassini just sucked (my code &lt;em&gt;couldn&#39;t&lt;/em&gt; be that bad). I whipped up a virtual directory in IIS and ran my tests again.&lt;/p&gt;
&lt;p&gt;Nope, it wasn&#39;t Cassini. Alright, so now let&#39;s get scientific. I pop open &lt;a href=&quot;http://www.red-gate.com/products/ants_profiler/index.htm&quot;&gt;ANTS&lt;/a&gt; and setup a profiling session on my virtual directory. I loaded the page a few times and, lo and behold, the worst offender screen pops up:&lt;/p&gt;
&lt;p&gt;&lt;a id=&quot;BLOGGER_PHOTO_ID_5632113825861421794&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://jdconley.com/blog-assets/imported/0e8af65acaef134307d84b6d.png&quot;&gt;&lt;img src=&quot;https://jdconley.com/blog-assets/imported/825aa880d8179194b3f085cc.png&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Wow! That&#39;s a long time (and a lot of hits). I was definitely right. I&#39;m hitting the database way too often. But, I know I saw the CPU racing... What the heck?&lt;/p&gt;
&lt;p&gt;Here&#39;s the offending code:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public static Feed GetOrCreateFeed(FeedsDataContext dc,string owner,FeedSourceType sourceType,string facebookId){var q = from f in dc.Feeds       where f.OwnerId == owner &amp;amp;&amp;amp;       f.FeedSourceType == (byte)sourceType &amp;amp;&amp;amp;       f.FacebookId == facebookId       select f;Feed existingItem = q.SingleOrDefault();...}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So I dug into the call graph a bit and found out the code causing by far the most damage was the creation of the LINQ query object for every call! The actual round trip to the database paled in comparison. Now that was, again, a &lt;em&gt;huge&lt;/em&gt; surprise. Check out the hit counts on this call – holy cow!&lt;/p&gt;
&lt;p&gt;&lt;a id=&quot;BLOGGER_PHOTO_ID_5632116728215770002&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://jdconley.com/blog-assets/imported/383f34aad87f62a7f2701d55.png&quot;&gt;&lt;img src=&quot;https://jdconley.com/blog-assets/imported/d586d9bc34215a3e984d9f81.png&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;1,176,879 calls to SqlVisitor.Visit. Over a million calls to anything for loading a page three times can&#39;t be good.&lt;/p&gt;
&lt;p&gt;I started doing some research. I remembered &lt;a href=&quot;http://blogs.msdn.com/ricom/archive/2007/07/05/dlinq-linq-to-sql-performance-part-4.aspx&quot;&gt;reading about&lt;/a&gt; using compiled LINQ to SQL queries for optimization a few months ago. I did a little more searching and ran into &lt;a href=&quot;http://devauthority.com/blogs/jwooley/archive/2007/09/05/75645.aspx&quot;&gt;this gem&lt;/a&gt; for anybody scared of lambda functions. &lt;em&gt;Warning, scary .NET 3.5 lambda functions ahead&lt;/em&gt; . Here&#39;s the magic fix:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;private static readonly Func&amp;lt;FeedsDataContext, string, FeedSourceType,string, IQueryable&amp;lt;Feed&amp;gt;&amp;gt; _compiledGet =CompiledQuery.Compile((FeedsDataContext dc, string owner,FeedSourceType sourceType, string facebookId) =&amp;gt;   from f in dc.Feeds   where f.OwnerId == owner &amp;amp;&amp;amp;   f.FeedSourceType == (byte)sourceType &amp;amp;&amp;amp;   f.FacebookId == facebookId   select f);public static Feed GetOrCreateFeed(FeedsDataContext dc,string owner,FeedSourceType sourceType,string facebookId){Feed existingItem = _compiledGet(dc, owner, sourceType, facebookId)   .SingleOrDefault();...}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If that&#39;s your first time seeing lambdas in C#, I feel for you. I&#39;d suggest trying them out and doing a lot of &lt;a href=&quot;http://www.google.com/search?q=c%23+lambda+functions&quot;&gt;research&lt;/a&gt;. That &lt;em&gt;simple&lt;/em&gt; change yielded the following result:&lt;/p&gt;
&lt;p&gt;&lt;a id=&quot;BLOGGER_PHOTO_ID_5632117288474594642&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://jdconley.com/blog-assets/imported/c4dae5ba17ce8170652ccb40.png&quot;&gt;&lt;img src=&quot;https://jdconley.com/blog-assets/imported/1f05627ab83e945d361e5521.png&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;That method is still by far the worst offender in the application, but is &lt;strong&gt;five times faster&lt;/strong&gt; than it was and barely registers on the CPU when the page loads. This one change netted sub second page rendering times which is good enough for me. Obviously I still have major issues, hitting the database way too often, but I&#39;m a big believer in not doing any premature optimization. But now, at least I&#39;m back in my comfort zone and am I/O bound.&lt;/p&gt;
&lt;p&gt;So, what have we learned? Never, ever, ever, ever, ever, ever, ever, ever, ever blindly edit code to fix performance issues. &lt;em&gt;Always&lt;/em&gt; run it through a profiler. No matter how much experience you have performance tuning, the worst offenders will still surprise you 99% of the time. Oh, and sometimes LINQ to SQL is slow at creating its query objects. Use compiled queries in these cases!&lt;/p&gt;
</content:encoded><category>.net</category><category>asp.net</category><category>linq</category><category>tuning</category></item>
<item><title>How much space are all my sql tables using?</title><link>https://jdconley.com/blog/how-much-space-are-all-my-sql-tables</link><guid isPermaLink="false">tag:blogger.com,1999:blog-1741199026308686058.post-7346749600347321380</guid><pubDate>Wed, 28 Nov 2007 01:35:00 GMT</pubDate><description>I deal with a few dozen databases on a daily basis. Often times I wonder &quot;What the heck is making this database 100GB?&quot; Sure, you can click around in Management Studio and find…</description><content:encoded>&lt;p&gt;I deal with a few dozen databases on a daily basis. Often times I wonder &quot;What the heck is making this database 100GB?&quot; Sure, you can click around in Management Studio and find figures on a table by table and index by index basis, but there has to be a better way!&lt;/p&gt;
&lt;p&gt;So, I asked a colleague of mine – who happens to be the guy that did all the database work on the SoapBox products and the best database dude I know. He didn&#39;t have a good answer for me so he whipped up this tiny script [Edit: After reading my blog he told me he actually adapted the script from one he found on the net that didn&#39;t quite work] in a few minutes. It makes my head spin. It&#39;s not perfect, but it&#39;s darn close.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;WITH table_space_usage( schema_name, table_name, index_name, used, reserved, ind_rows, tbl_rows )AS (SELECT s.Name    , o.Name    , coalesce(i.Name, &#39;HEAP&#39;)    , p.used_page_count * 8    , p.reserved_page_count * 8    , p.row_count    , case when i.index_id in ( 0, 1 ) then p.row_count else 0 end FROM sys.dm_db_partition_stats p INNER JOIN sys.objects as o   ON o.object_id = p.object_id INNER JOIN sys.schemas as s   ON s.schema_id = o.schema_id LEFT OUTER JOIN sys.indexes as i   on i.object_id = p.object_id and i.index_id = p.index_idWHERE o.type_desc = &#39;USER_TABLE&#39;  and o.is_ms_shipped = 0)SELECT t.schema_name    , t.table_name    , t.index_name    , sum(t.used) as used_in_kb    , sum(t.reserved) as reserved_in_kb    , case grouping(t.index_name)when 0 then sum(t.ind_rows)else sum(t.tbl_rows) end as rowsFROM table_space_usage as tGROUP BY      t.schema_name    , t.table_name    , t.index_nameWITH ROLLUPORDER BY     grouping(t.schema_name)   , t.schema_name   , grouping(t.table_name)   , t.table_name   , grouping(t.index_name)   , t.index_name
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I hope that hurts your head as much as it does mine. Just goes to show that I&#39;m no SQL guru, I guess. But hey, if you ever want to know where that space is going in your database, this script will tell you!&lt;/p&gt;
</content:encoded><category>random</category><category>utility</category></item>
<item><title>Photo Feeds Facebook Application</title><link>https://jdconley.com/blog/photo-feeds-facebook-application</link><guid isPermaLink="false">tag:blogger.com,1999:blog-1741199026308686058.post-7087191807678130888</guid><pubDate>Tue, 27 Nov 2007 17:48:00 GMT</pubDate><description>I&#39;ve built quite a few applications for Facebook. These include SoapBox, Friend Photosaver, Photozap, and my latest creation (late last night) is called Photo Feeds.Photo…</description><content:encoded>&lt;p&gt;I&#39;ve built quite a few applications for Facebook. These include &lt;a href=&quot;http://www.facebook.com/apps/application.php?id=2447886974&quot;&gt;SoapBox&lt;/a&gt;, &lt;a href=&quot;http://www.facebook.com/apps/application.php?id=2466327790&quot;&gt;Friend Photosaver&lt;/a&gt;, &lt;a href=&quot;http://www.facebook.com/apps/application.php?id=5577408502&quot;&gt;Photozap&lt;/a&gt;, and my latest creation (late last night) is called &lt;a href=&quot;http://www.facebook.com/apps/application.php?id=7515202213&quot;&gt;Photo Feeds&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a id=&quot;BLOGGER_PHOTO_ID_5632109571316005058&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://jdconley.com/blog-assets/imported/afac6ada2089089f450ccec0.png&quot;&gt;&lt;img src=&quot;https://jdconley.com/blog-assets/imported/afac6ada2089089f450ccec0.png&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Photo feeds, as of the written-in-12-hours v1.0, automatically creates RSS feeds for the photos of you and your friends. You can subscribe to these feeds using anything that supports RSS photos. Your news reader, your favorite photo screen saver, windows vista sidebar, google sidebar, digital photo frames, etc, etc.&lt;/p&gt;
&lt;p&gt;In the near future I hope to make this more compelling with new features including adding deeper integration into your Facebook profile and publishing to the Facebook news feed. In addition, I&#39;ll be integrating the three photo products (Friend Photosaver, Photozap, and Photo Feeds) to provide a rich add-on suite to Facebook Photos aimed at getting your photos to your desktop outside of Facebook.&lt;/p&gt;
&lt;p&gt;Of course, this latest application was written using .NET Framework 3.5, Visual Studio 2008, and my top secret (though soon open source) asynchronous Facebook library. If you&#39;re a .NET developer interested in writing Facebook apps let me know and I&#39;ll be sure to blog about the technical details in the future. There doesn&#39;t seem to be many of us in the Facebook world.&lt;/p&gt;
</content:encoded><category>.net</category><category>facebook</category></item>
<item><title>FileVersionInfo - My Long Lost Friend</title><link>https://jdconley.com/blog/fileversioninfo-my-long-lost-friend</link><guid isPermaLink="false">tag:blogger.com,1999:blog-1741199026308686058.post-6128067537066896627</guid><pubDate>Mon, 26 Nov 2007 21:31:00 GMT</pubDate><description>I&#39;ve been doing .NET development professionally since the first public beta release of the 1.0 framework. That&#39;s... well, a long time. It constantly amazes me how big the…</description><content:encoded>&lt;p&gt;I&#39;ve been doing .NET development professionally since the first public beta release of the 1.0 framework. That&#39;s... well, a long time. It constantly amazes me how big the framework really is. There are a number of times I&#39;ve written tens or hundreds of lines of code for a task that I later realized – or was smacked over the head with by a colleague with – that were in the framework. Heck, even after writing my &lt;a href=&quot;https://jdconley.com/blog/aspnet-centric-extensions&quot;&gt;Extension Methods&lt;/a&gt; post a couple months ago some friendly readers &lt;a href=&quot;https://jdconley.com/blog/aspnet-centric-extensions#2&quot;&gt;pointed out&lt;/a&gt; how I was writing too much code.&lt;/p&gt;
&lt;p&gt;Today, I was updating a client&#39;s web application to show the version number at the bottom of the screen based on the actual version that was running (it used to just be hard coded). The version number on the site was supposed to show the full revision of the assembly – which is stored in the assembly &lt;strong&gt;file version&lt;/strong&gt; . The process to build the web site follows Microsoft version standards so the assembly version number does not necessarily change with each revision, but the file version does. Therefore, the normal &lt;em&gt;System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString()&lt;/em&gt; isn&#39;t really the version number we want to display.&lt;/p&gt;
&lt;p&gt;But how do you get the file version? Well, with &lt;em&gt;System.Diagnostics.FileVersionInfo.GetVersionInfo&lt;/em&gt; of course! I swear I have looked for how to do this numerous times with only win32 responses to my query. Anyway, apparently it&#39;s dirt simple. This time I ran into &lt;a href=&quot;http://www.thescripts.com/forum/thread492012.html&quot;&gt;this thread&lt;/a&gt; with the answer. Check out the &lt;a href=&quot;http://msdn2.microsoft.com/en-us/library/system.diagnostics.fileversioninfo%28vs.90%29.aspx&quot;&gt;System.Diagnostics.FileVersionInfo&lt;/a&gt; class for more info. Duh!&lt;/p&gt;
&lt;p&gt;I leave you with this to ponder: WHY, WHY, WHY is this feature not exposed through System.IO.FileInfo or some other class that makes sense (and I did check in Reflector to be sure I wasn&#39;t mad)?!&lt;/p&gt;
</content:encoded><category>.net</category><category>utility</category></item>
<item><title>Command Line VS 2008 Project Upgrade Tool</title><link>https://jdconley.com/blog/command-line-vs-2008-project-upgrade</link><guid isPermaLink="false">tag:blogger.com,1999:blog-1741199026308686058.post-2481574914174471447</guid><pubDate>Wed, 21 Nov 2007 18:52:00 GMT</pubDate><description>I&#39;ve converted a few projects to 2008 RTM now (from 2003 to 2005 to 2008 beta projects), and I wish John Robbins had published this blog earlier. For those of us that don&#39;t…</description><content:encoded>&lt;p&gt;I&#39;ve converted a few projects to 2008 RTM now (from 2003 to 2005 to 2008 beta projects), and I wish John Robbins had published &lt;a href=&quot;http://www.wintellect.com/cs/blogs/jrobbins/archive/2007/11/21/easily-converting-to-visual-studio-2008.aspx&quot;&gt;this blog&lt;/a&gt; earlier. For those of us that don&#39;t like clicking in things he presents a built-in command line switch on devenv to upgrade solutions. I decided to take it to the next level.&lt;/p&gt;
&lt;p&gt;I built a small &lt;a href=&quot;https://docs.google.com/viewer?a=v&amp;pid=explorer&amp;chrome=true&amp;srcid=0B7Ew2HKAAmajMTMyZjA1MjAtMWJhNi00NjMwLWI0ZWYtYWNiNDRmYjQzYWNl&amp;hl=en_US&quot;&gt;command line application&lt;/a&gt; that recursively scans a directory for solution files and prompts you to upgrade all of them. I tried it on a bunch of my solutions and it seemed to work pretty well.&lt;/p&gt;
&lt;p&gt;To use the tool you just run it from the command line and specify the directory where you want to start searching. Or you can specify no arguments to search the current working directory.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    upgrader.exe c:\root\of\your\tree
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;or&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    upgrader.exe
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That&#39;s it! Quick and easy. The output will look something like:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    Searching for solutions under c:\svn\websites Upgrade &quot;c:\svn\websites\mysite\my.sln&quot;? [Y/N] n Skipped &quot;c:\svn\websites\mysite\my.sln&quot; Upgrade &quot;c:\svn\websites\broken\site.sln&quot;? [Y/N] y Converting &quot;c:\svn\websites\broken\site.sln&quot; Unable to convert solution &quot;c:\svn\websites\broken\site.sln&quot; Check out the errors in the UpgradeLog.xml file. Upgrade &quot;c:\svn\websites\ok\site.sln&quot;? [Y/N] y Converting &quot;c:\svn\websites\ok\site.sln&quot; Converted &quot;c:\svn\websites\ok\site.sln&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Well, that&#39;s my simple app that took just a few minutes to write and saved the pain of many clicks through a wizard. &lt;a href=&quot;http://jdconley.com/upgrader2008.zip&quot;&gt;Download it here&lt;/a&gt;.&lt;/p&gt;
</content:encoded><category>.net</category><category>utility</category></item>
<item><title>More Visual Studio 2008 Beta 2 to RTM Upgrade Gotchas</title><link>https://jdconley.com/blog/more-visual-studio-2008-beta-2-to-rtm</link><guid isPermaLink="false">tag:blogger.com,1999:blog-1741199026308686058.post-2140608852551935922</guid><pubDate>Wed, 21 Nov 2007 00:05:00 GMT</pubDate><description>Yesterday I posted on the first thing I ran into. Today I ported another project and hit a couple more snags. Linq to Sql Unicode Byte Header Linq to Sql Add/Remove Method…</description><content:encoded>&lt;p&gt;Yesterday I posted on the first thing I ran into. Today I ported another project and hit a couple more snags.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Linq to Sql Unicode Byte Header&lt;/li&gt;
&lt;li&gt;Linq to Sql Add/Remove Method Changes&lt;/li&gt;
&lt;li&gt;ASP.NET Listview Changed from itemContainer to itemPlaceholder&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Linq to Sql Unicode Byte Header&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The xml document that makes up the Linq to Sql dbml file is declared to be in unicode format. For some reason my file was not saved with the unicode byte header. Apparently this didn&#39;t matter to the beta 2 framework, but in RTM release the project failed to build and double clicking on the designer caused the error &quot;There is no Unicode byte order mark. Cannot switch to Unicode.&quot;&lt;/p&gt;
&lt;p&gt;When the error occurs it opens the dbml file as XML. So, I just moved my cursor to the first position. Hit &lt;em&gt;enter&lt;/em&gt; then &lt;em&gt;backspace&lt;/em&gt; and saved the file. Visual Studio 2008 RTM put the Unicode Byte Header in for me and everything was kosher.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Linq to Sql Add/Remove Method Changes&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The Linq to Sql Table&amp;lt;T&amp;gt; and ITable has changed the signature for adding and removing entities. Instead of the &lt;em&gt;Add&lt;/em&gt; and &lt;em&gt;Remove&lt;/em&gt; methods there are now &lt;em&gt;InsertOnSubmit&lt;/em&gt; and &lt;em&gt;DeleteOnSubmit&lt;/em&gt; . This makes sense, as it was not obvious what Add and Remove would do. These new names make a lot of sense to me and were outlined in a &lt;a href=&quot;http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=2060651&amp;SiteID=1&quot;&gt;msdn forum posting&lt;/a&gt; a few months ago.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;ASP.NET Listview Changed from itemContainer to itemPlaceholder&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;It looks like a few bloggers already beat me to this one, but the behavior of the itemContainer in an ASP.NET Listview has changed and the new control ID you have to use is called itemPlaceholder. Daniel Moth has a good description &lt;a href=&quot;http://www.danielmoth.com/Blog/2007/11/item-placeholder-must-be-specified-on.html&quot;&gt;on his blog here&lt;/a&gt;. The annoying thing about this change for me was that it showed up at runtime, and not compile time. Though the runtime message is pretty descriptive: System.InvalidOperationException: An item placeholder must be specified on ListView &#39;ListView1&#39;. Specify an item placeholder by setting a control&#39;s ID property to &quot;itemPlaceholder&quot;. The item placeholder control must also specify runat=&quot;server&quot;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Wrap Up&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Well, that&#39;s all I&#39;ve run into so far. I&#39;m sure I&#39;ll find more issues as I wrote quite a bit of (production) code under 2008 Beta 2. I&#39;ll make sure to summarize any more findings here.&lt;/p&gt;
</content:encoded><category>.net</category><category>asp.net</category><category>linq</category><category>random</category></item>
<item><title>Small Gotcha in .NET Framework 3.5 Beta 2 to RTM Upgrade</title><link>https://jdconley.com/blog/small-gotcha-in-net-framework-35-beta-2</link><guid isPermaLink="false">tag:blogger.com,1999:blog-1741199026308686058.post-4154510686697844042</guid><pubDate>Tue, 20 Nov 2007 00:07:00 GMT</pubDate><description>Visual Studio 2008 was officially released today to MSDN subscribers so I took the leap and did the upgrade. I ran into an issue with a simple fix that I thought everyone…</description><content:encoded>&lt;p&gt;Visual Studio 2008 was officially released today to MSDN subscribers so I took the leap and did the upgrade. I ran into an issue with a simple fix that I thought everyone should be aware of. You&#39;ll get an error message stating: &quot;Could not load file or assembly &#39;System.Data.DataSetExtensions, Version=2.0.0.0...&quot;. This is somewhat cryptic, but easy to fix.&lt;/p&gt;
&lt;p&gt;If you have a web project that was running under .NET 3.5 beta 2 you will have an assembly reference as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;compilation&amp;gt;&amp;lt;assemblies&amp;gt;  ...  &amp;lt;add assembly=&quot;System.Data.DataSetExtensions, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089&quot;/&amp;gt;&amp;lt;/assemblies&amp;gt;&amp;lt;/compilation&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notice the version number is 2.0.0.0. This was apparently changed at the RTM and the version number should be 3.5.0.0 like:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;compilation&amp;gt;&amp;lt;assemblies&amp;gt;  ...  &amp;lt;add assembly=&quot;System.Data.DataSetExtensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089&quot;/&amp;gt;&amp;lt;/assemblies&amp;gt;&amp;lt;/compilation&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
</content:encoded><category>.net</category><category>asp.net</category></item>
<item><title>ASP.NET MVC Framework</title><link>https://jdconley.com/blog/aspnet-mvc-framework</link><guid isPermaLink="false">tag:blogger.com,1999:blog-1741199026308686058.post-8456221550217150738</guid><pubDate>Tue, 13 Nov 2007 17:02:00 GMT</pubDate><description>I&#39;m a huge fan of Test Driven Development and I&#39;ve been looking forward to the ASP.NET MVC (Model View Controller) Framework to increase the level of testability of web…</description><content:encoded>&lt;p&gt;I&#39;m a huge fan of Test Driven Development and I&#39;ve been looking forward to the ASP.NET MVC (Model View Controller) Framework to increase the level of testability of web projects. Scott Gu just posted a &lt;a href=&quot;http://weblogs.asp.net/scottgu/archive/2007/11/13/asp-net-mvc-framework-part-1.aspx&quot;&gt;great and frighteningly in-depth article&lt;/a&gt; – I don&#39;t know how he has the time. If you like releasing quality/tested, code, check it out. If you&#39;re not a developer, make your developers look at it.&lt;/p&gt;
</content:encoded><category>asp.net</category><category>random</category></item>
<item><title>Dvorak&#39;s Gone Mad</title><link>https://jdconley.com/blog/dvoraks-gone-mad</link><guid isPermaLink="false">tag:blogger.com,1999:blog-1741199026308686058.post-7724535890622942356</guid><pubDate>Fri, 09 Nov 2007 21:51:00 GMT</pubDate><description>Maybe I&#39;m just young, arrogant, and naive, but I think John&#39;s getting a little senile. In his latest rant for his PC Mag column he bashes Google&#39;s plans for the Open Handset…</description><content:encoded>&lt;p&gt;Maybe I&#39;m just young, arrogant, and naive, but I think John&#39;s getting a little senile. In his latest &lt;a href=&quot;http://www.pcmag.com/article2/0,2704,2212850,00.asp&quot;&gt;rant&lt;/a&gt; for his &lt;a href=&quot;http://www.pcmag.com/category2/0,2705,3574,00.asp&quot;&gt;PC Mag column&lt;/a&gt; he bashes Google&#39;s plans for the Open Handset Alliance with the title &quot;The Google Phone is Doomed&quot;. Go read that if you haven&#39;t already and work your way back here. Don&#39;t get me wrong, I&#39;m not convinced the project will work either – more on that later, but his reasoning confuses me.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Why Dvorak Thinks it Won&#39;t Work&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Google isn&#39;t charismatic&lt;/li&gt;
&lt;li&gt;Smartphones suck&lt;/li&gt;
&lt;li&gt;Nobody wants the internet on their phone&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Google isn&#39;t charismatic? People don&#39;t love Google? Really? Google has more mindshare than pretty much any internet company out there. Ok, so they put out a crappy social networking tool called Orkut that nobody has heard of. I&#39;m not sure how that relates to the potential success of an open phone product.&lt;/p&gt;
&lt;p&gt;Smartphones currently suck. I definitely won&#39;t be arguing with that. The operating system user interfaces are crap and the software packages suck. However, I don&#39;t get how that has anything to do with a vaporware smarthpone due out some time in the future. If anything, an open platform should lead to a bunch of startups trying to build the next great phone interface. If they can pull it off, this should jumpstart an entire industry of reform. Apple did some good things with the iPhone. I see no reason why the same can&#39;t happen with OHA.&lt;/p&gt;
&lt;p&gt;I&#39;m not sure what year he&#39;s living in, but pondering why anyone would want internet on the phone when they could use the phone is just plain dumb. How do you know the phone number of the restaurant without the internet (or finding a phone book somewhere)? And why would I want to talk to someone when I can get more information myself on Google or [insert name of search startup here]? Maybe it&#39;s just me, but this seems like someone arguing to keep their fax machine instead of getting email, or keep their email instead of getting instant messaging.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Why I think it might not work&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Alright, so maybe I don&#39;t agree with everything John brings up, but I do agree with one. Google wants to roll up the entire mobile market. The carriers, the operating systems, the software, and the hardware manufacturers. I don&#39;t see one of the biggest industries in the world taking that lying down.&lt;/p&gt;
&lt;p&gt;In addition to the huge hurdles on the business side of things the technical challenges are staggering. Phones are not simple platforms to build on. And from what I&#39;ve seen Google has yet to produce a large, complex, consumer facing product. They have a great back end platform and a boatload of itty bitty – dare I say widget – sized front end applications. An operating system and SDK that runs on a phone will prove to be a huge task, indeed.&lt;/p&gt;
&lt;p&gt;In any case, &quot;doomed&quot; is pretty uncalled for. Of course, I did read his article, look at his ads, and now all of you are going to head over there too. So, I guess that&#39;s a success... And hey, I&#39;m just a punk kid anyway! :)&lt;/p&gt;
</content:encoded><category>business</category><category>random</category></item>
<item><title>Vista Rant</title><link>https://jdconley.com/blog/vista-rant</link><guid isPermaLink="false">tag:blogger.com,1999:blog-1741199026308686058.post-8612167056838636292</guid><pubDate>Sun, 07 Oct 2007 20:23:00 GMT</pubDate><description>Next month Vista will have been out in RTM for a year (it was released on 11/30/2006 to the volume/dev world). Why is it then, that it still doesn&#39;t work?When I originally…</description><content:encoded>&lt;p&gt;Next month Vista will have been out in RTM for a year (it was released on 11/30/2006 to the volume/dev world). Why is it then, that it still doesn&#39;t work?&lt;/p&gt;
&lt;p&gt;When I originally bought my current workstation, almost two years ago, I set it up with four partitions (I had a terrabyte RAID). I installed XP Pro 32 bit for games and Windows Server 2003 x64 for development. I left two open partitions, one for Vista, and one for some flavor of Linux. For the first six months of its life I spent most of my time in XP Pro x86. It worked, but I was wasting my fancy 64 bit hardware!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The beginnings — x64, take 1&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;On &lt;a href=&quot;https://jdconley.com/blog/fun-installing-vista-beta-2-on-amd-x64&quot;&gt;June 6 2006&lt;/a&gt; I blogged about my experience installing Vista on my workstation. At the time it went reasonably well. Heck, my system passed the hardware compatibility wizard with flying colors! However, I really should have posted some follow-ups.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A week later — x64, take 2&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;After I started actually &lt;em&gt;using&lt;/em&gt; Vista, it started crashing, a lot. I&#39;d get at least one blue screen a day. I looked at the minidumps and they were all related to one of my NVidia drivers. It would be either the NIC or the sound or the SATA or the RAID — yeah, pretty much everything that comes with &lt;a href=&quot;http://www.pcstats.com/artvnl.cfm?articleID=1903&quot;&gt;my motherboard&lt;/a&gt; (I bought it for the pretty colors). One day I noticed a Windows update for my NVidia RAID drivers. &quot;Cool&quot;, I thought. Maybe they sped them up or improved stability. The drivers installed; my system rebooted; it bluescreened; repeat. After much frustration I switched to XP Pro x64.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A month later — x64, screw you&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;XP Pro x64 was fairly stable, but I still had serious issues with the interaction of the drivers. If I was using the network heavily and then started using the sound card heavily: Kablammo! BSOD! I sort of learned how to work around this and would mute my music before doing anything intensive over the network. Needless to say this was very annoying. I switched to XP Pro x86.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;December, 2006 — Vista x64 RTM install&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&quot;Ok, Vista is RTM now&quot;, I thought. &quot;Surely NVidia has got their act together now!&quot; They&#39;re working closely with Microsoft on this stuff, right?!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;December, 2006 — Vista x86 RTM install&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&quot;Ok, x64 is the bastard child of hardware&quot;, I thought. &quot;Surely this will work.&quot;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;December, 2006 — Back to the trusty XP Pro x86 partition&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Yeah, back on XP. I&#39;ll spare you the details.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;August, 2007 — Vista x86 install&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&quot;Ok, it&#39;s been a million computer years now&quot;, I thought. &quot;Surely all my crash reports and support incidents have caused some bug fixes.&quot; Not so much. I even installed it on a PATA drive, no RAID required. To add to the pain, I also purchased a &lt;a href=&quot;http://www.dlink.com/products/?sec=0&amp;pid=566&quot;&gt;D-Link DWA-130 USB Wireless N Adapter&lt;/a&gt; for my desktop at the same time. I can&#39;t pass on the promise of speed with no wires. &quot;What?! No Vista drivers?! I quit!&quot; What&#39;s with a new product (released in July 2007) not having Vista drivers? Oh, there are beta ones available now — they don&#39;t work either.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;August, 2007 — XP x86 Pro for life&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;After over a year of struggling and giving it a chance, I&#39;ve given up. Either Microsoft or these hardware/driver vendors need to get their heads out of their asses, take some initiative, and fix this crap. I&#39;m officially a hateful bastard until someone shows me some reason not to be.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;October, 2007 — The world should know&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I wrote this blog. It feels good to vent. Much cheaper than a therapist.&lt;/p&gt;
</content:encoded><category>random</category><category>windows</category></item>
<item><title>Asyncify Your Code</title><link>https://jdconley.com/blog/asyncify-your-code</link><guid isPermaLink="false">tag:blogger.com,1999:blog-1741199026308686058.post-188156924369495615</guid><pubDate>Sat, 29 Sep 2007 06:01:00 GMT</pubDate><description>Asyncify your code. Everybody&#39;s doing it. (Chicks|Dudes)&#39;ll dig it. It&#39;ll make you cool. Pretty much everything I build these days is asynchronous in nature. In SoapBox…</description><content:encoded>&lt;p&gt;Asyncify your code. Everybody&#39;s doing it. (Chicks|Dudes)&#39;ll dig it. It&#39;ll make you cool.&lt;/p&gt;
&lt;p&gt;Pretty much everything I build these days is asynchronous in nature. In &lt;a href=&quot;http://soapbox.im/&quot;&gt;SoapBox&lt;/a&gt; products we are often waiting on some sort of IO to complete. We wait for XMPP data to be sent and received, database queries to complete, log files to be written, DNS servers to respond, .NET to negotiate Tls through a &lt;a href=&quot;http://www.leastprivilege.com/SslStreamSample.aspx&quot;&gt;SslStream&lt;/a&gt;, and much more. Today I&#39;ll be talking about a recent walk down Asynchronous Lane: the &lt;a href=&quot;https://docs.google.com/viewer?a=v&amp;pid=explorer&amp;chrome=true&amp;srcid=0B7Ew2HKAAmajYjIzNmE4MDYtYWFiMy00Nzk1LTg3MjUtODAzNGY5ZmRmN2I2&amp;hl=en_US&quot;&gt;AsynchronousProcessGate&lt;/a&gt; (if you don&#39;t like reading just download &lt;a href=&quot;https://docs.google.com/viewer?a=v&amp;pid=explorer&amp;chrome=true&amp;srcid=0B7Ew2HKAAmajYjIzNmE4MDYtYWFiMy00Nzk1LTg3MjUtODAzNGY5ZmRmN2I2&amp;hl=en_US&quot;&gt;the package&lt;/a&gt; for source code goodness).&lt;/p&gt;
&lt;p&gt;I ran into a problem while working on a new web application for Coversant. I needed to execute an extremely CPU and IO intesive process: creating and digitally signing a self extracting compressed file -- AKA The Package Service. This had to happen in an external process, and it had to scale (this application is publicly available on our consumer facing &lt;a href=&quot;http://soapbox.im/signup.aspx&quot;&gt;web site&lt;/a&gt;). Here&#39;s a basic sequence of the design I came up with:&lt;/p&gt;
&lt;p&gt;&lt;a id=&quot;BLOGGER_PHOTO_ID_5632098975080183362&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://jdconley.com/blog-assets/imported/f354242a4442521fede8c951.jpg&quot;&gt;&lt;img src=&quot;https://jdconley.com/blog-assets/imported/b0e463757dee3f268b91e3d1.jpg&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Do you notice the large holes in the activation times? That&#39;s because we&#39;re asynchronous! The BeginCreatePackage web service method the page calls exits as soon as the BeginExecute method exits, which is as right when the process starts. That means we&#39;re not tying up any threads in our .NET threadpools at any layer of our application during the time a task is executing. That&#39;s a Good Thing™.&lt;/p&gt;
&lt;p&gt;At this point I&#39;m used to writing highly asynchronous/threaded code. However, I still wouldn&#39;t call it easy. Why do it? I&#39;d say there are three main reasons.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;To provide a smooth user experience. The last thing a developer wants is for his/her software to appear sluggish. There&#39;s nothing worse than opening Windows Explorer and watching your screen turn white (that application is NOT very asynchronous).&lt;/li&gt;
&lt;li&gt;To fully and most appropriately utilize the resources of the platform (Runtime/OS/Hardware). To scale vertically, you might call it.&lt;/li&gt;
&lt;li&gt;Because it makes you cool. AKA: To bill a lot more on consulting engagements.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Microsoft &lt;a href=&quot;http://msdn2.microsoft.com/en-us/library/ms228969.aspx&quot;&gt;recommends two asynchronous design patterns&lt;/a&gt; for .NET developers exposing Asynchronous interfaces. These can be found on various classes throughout the framework. The &lt;a href=&quot;http://msdn2.microsoft.com/en-us/library/hkasytyf.aspx&quot;&gt;Event Based&lt;/a&gt; pattern comes highly recommended from Microsoft and can be found all over new components they build (like the &lt;a href=&quot;http://msdn2.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx&quot;&gt;BackgroundWorker&lt;/a&gt;). Personally I think the event based pattern is overrated. The hassle of managing events and not knowing if the &lt;a href=&quot;https://jdconley.com/blog/simpler-isnt-always-better&quot;&gt;completed event will even fire&lt;/a&gt; typically steers me away from this one. However, it is certainly easier for those who are new to the asynchronous world. This pattern is also quite useful in many situations in Windows Forms and ASP.NET applications, leaving the responsibility of the thread switching to the asynchronous implementation (the events are supposed to be called in the thread/context that made the Async request -- determined by the &lt;a href=&quot;https://jdconley.com/blog/simpler-isnt-always-better&quot;&gt;AsyncOperationsManager&lt;/a&gt;). If you&#39;ve ever used the &lt;a href=&quot;http://msdn2.microsoft.com/en-us/library/system.componentmodel.isynchronizeinvoke.aspx&quot;&gt;ISynchronizeInvoke&lt;/a&gt; interface on a Winforms Control or manually done &lt;a href=&quot;http://odetocode.com/Blogs/scott/archive/2005/06/16/1656.aspx&quot;&gt;Async ASP.NET Pages&lt;/a&gt; you can really appreciate the ease of use of this new pattern...&lt;/p&gt;
&lt;p&gt;The second recommended pattern, and usually my preference, is called the &lt;a href=&quot;http://msdn2.microsoft.com/en-us/library/ms228975.aspx&quot;&gt;IAsyncResult pattern&lt;/a&gt;. IAsyncResult and I have a very serious love/hate relationship. I&#39;ve spent many days with my IM status reading &quot;Busy - Asyncifying&quot; due to this one. But, in the end, it produces a simple interface for performing asynchronous operations and a callback when the operation is complete (or maybe timed out or canceled). Typically you&#39;ll find IAsyncResult interfaces on the more &quot;hard core&quot; areas of the framework exposing operations such as Sockets, File IO, and streams in general. This is the pattern I used for the Asynchronous Process Gate in the Package Service.&lt;/p&gt;
&lt;p&gt;The Package Service has a user interface (an AJAXified asynchronous ASP.NET 2.0 page) which calls an &lt;a href=&quot;http://msdn2.microsoft.com/en-us/library/98t3s469.aspx&quot;&gt;asynchronous web service&lt;/a&gt;. The web service calls another asynchronous class which wraps a few asynchronous operations through the AsynchronousProcessGate and other async methods (i.e. to register a new user account) and exposes a single IAsyncResult interface to the web service.&lt;/p&gt;
&lt;p&gt;Confused yet? Read that last paragraph again and &lt;a href=&quot;https://jdconley.com/blog-assets/imported/f354242a4442521fede8c951.jpg&quot;&gt;re-look at the sequence&lt;/a&gt;. In order to make this whole thing scale it had to be asynchronous or we&#39;d be buying a whole rack of servers to support even a modest load. Also because of the nature of the asynchronous operation (high cpu/disk IO) it had to be configurably queued/throttled. I went through a few possible designs on paper. But in the end I chose to push it down as far as possible. The AsynchronousProcessGate, quite simply, only allows a set number of processes to execute simultaneously, the number of CPU&#39;s reported by System.Environment.ProcessorCount by default. It does this by exposing the IAsyncResult pattern for familiar consumption. The piece of magic used internally is something we came up with after writing a lot of asynchronous code: LazyAsyncResult&amp;lt;T&amp;gt;.&lt;/p&gt;
&lt;p&gt;LazyAsyncResult&amp;lt;T&amp;gt; provides a generic implementation of IAsyncResult. It manages your state, your caller&#39;s state, and the completion events. It also uses &lt;a href=&quot;http://www.bluebytesoftware.com/blog/PermaLink,guid,df20d0c7-4bf7-443e-8601-b6aa4355a9b1.aspx&quot;&gt;Joe Duffy&#39;s LazyInit stuff&lt;/a&gt; for better performance (initializing the WaitHandle is relatively expensive and usually not needed).&lt;/p&gt;
&lt;p&gt;Using the asynchronous process gate is straight forward if you&#39;re used to the Begin/End IAsyncResult pattern. You create an instance of the class, and call BeginExecuteProcess with your ProcessStartInfo. When the process is complete you will get your AsyncCallback, or you can also wait on the IAsyncResult.WaitHandle that is returned from BeginExecuteProcess. You then call EndExecuteProcess and the instance of Process that was used is returned. If an exception occurred asynchronously, it will be thrown when you call EndExecuteProcess.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Begin Code:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;static void StartProcesses(){   AsynchronousProcessGate g = new AsynchronousProcessGate();   while (!_shutdown)   {       //keep twice as many queued as we have cpu&#39;s.       //for a real, CPU or IO intensive, operation       //you shouldn&#39;t do any throttling before the gate.       //that&#39;s what the gate is for!       if (g.PendingCount &amp;lt; g.AllowedInstances * 2)           g.BeginExecuteProcess(               new ProcessStartInfo(&quot;notepad.exe&quot;),               10000,               ProcessCompleted,               g);       else           System.Threading.Thread.Sleep(100);   }}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;The End Code:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;static void ProcessCompleted(IAsyncResult ar){   try   {       AsynchronousProcessGate g =           (AsynchronousProcessGate)ar.AsyncState;       using (Process p = g.EndExecuteProcess(ar))           Console.WriteLine(&quot;Exited with code: &quot; +               p.ExitCode + &quot;. &quot; +               g.PendingCount + &quot; notepads pending.&quot;);   }   catch (Exception ex)   {       Console.WriteLine(&quot;(&quot;            + ex.GetType().ToString()            + &quot;) - &quot;   ex.Message);   }}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Phew! After all that, the end result for SoapBox: a single self extracting digitally signed file someone can download. Oh, and a simple library you can use as an Asynchronous Process Gate! Enjoy. Look, another &lt;a href=&quot;https://docs.google.com/viewer?a=v&amp;pid=explorer&amp;chrome=true&amp;srcid=0B7Ew2HKAAmajYjIzNmE4MDYtYWFiMy00Nzk1LTg3MjUtODAzNGY5ZmRmN2I2&amp;hl=en_US&quot;&gt;download link&lt;/a&gt; so you don&#39;t even have to scroll back up. How nice am I?&lt;/p&gt;
</content:encoded><category>.net</category><category>async</category><category>tuning</category></item>
<item><title>Stringbuildify!</title><link>https://jdconley.com/blog/stringbuildify</link><guid isPermaLink="false">tag:blogger.com,1999:blog-1741199026308686058.post-6881000841619034399</guid><pubDate>Thu, 27 Sep 2007 21:48:00 GMT</pubDate><description>A task that I often end up doing when coding an actual web site (i.e. not writing a sample or some such) is adding client script to a page/control in codebehind using the…</description><content:encoded>&lt;p&gt;A task that I often end up doing when coding an actual web site (i.e. not writing a sample or some such) is adding client script to a page/control in codebehind using the &lt;a href=&quot;http://msdn2.microsoft.com/en-us/library/ms178207.aspx&quot;&gt;ClientScriptManager&lt;/a&gt;. Let&#39;s say you&#39;ve got the following alert script you want to add to the page so you can use it in a control:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function doAlert(){ alert(&#39;welcome!&#39;);}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Well, there are now a number of ways to get this into your page, but the quickest, in-line way is to use the ClientScriptManager. Like so:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;if (!Page.ClientScript.IsClientScriptBlockRegistered(   this.GetType(), &quot;alert&quot;)){   System.Text.StringBuilder sb = new System.Text.StringBuilder();   sb.Append(&quot;function doAlert() {&quot;);   sb.Append(&quot;alert (&#39;welcome!&#39;); }&quot;);   Page.ClientScript.RegisterClientScriptBlock(       this.GetType(), &quot;alert&quot;, sb.ToString(), true);}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ok, so that&#39;s a bit contrived. You&#39;re not going to use a StringBuilder for something that simple. But, with a more complicated script you probably would, especially if the script will be different depending on the state of the page.&lt;/p&gt;
&lt;p&gt;I had a little Winforms utility sitting around I&#39;ve been using for a while to automate that process for me, and I decided to put it up on the web. So, here you go: &lt;a href=&quot;http://jdconley.com/stringbuildify&quot;&gt;http://jdconley.com/stringbuildify&lt;/a&gt;. You feed the engine a multi-line string (like a script) and it gives you back a StringBuilder with everything properly escaped and such. The code&#39;s a bit of a mess at this second, that&#39;s why I didn&#39;t post it. Enjoy!&lt;/p&gt;
</content:encoded><category>.net</category><category>asp.net</category><category>utility</category></item>
<item><title>ASP.NET Centric Extensions</title><link>https://jdconley.com/blog/aspnet-centric-extensions</link><guid isPermaLink="false">tag:blogger.com,1999:blog-1741199026308686058.post-2009462146535283982</guid><pubDate>Wed, 19 Sep 2007 23:05:00 GMT</pubDate><description>I&#39;ve been loving the new Extension Methods in Orcas. If you haven&#39;t had the pleasure of working with them, well, you&#39;re really missing out. They are utility at its finest. Here…</description><content:encoded>&lt;p&gt;I&#39;ve been loving the new &lt;a href=&quot;http://weblogs.asp.net/scottgu/archive/2007/03/13/new-orcas-language-feature-extension-methods.aspx&quot;&gt;Extension Methods&lt;/a&gt; in Orcas. If you haven&#39;t had the pleasure of working with them, well, you&#39;re really missing out. They are utility at its finest. Here is a list of my favorite extensions I&#39;ve written thus far.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;URLEncode&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Ok, I know this sounds stupid, but for some reason I really hate typing HttpUtility.UrlEncode(myString) all over the place so I wrote this extension.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public static string UrlEncode(this string toEncode){   return HttpUtility.UrlEncode(toEncode);}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;ToHexString&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;For some reason my memory for .NET format strings really sucks. I blame Intellisense. I &lt;em&gt;always&lt;/em&gt; forget how to hex encode integers. In case you&#39;re wondering, this is quite useful for giving users short strings that can be very unique and directly represent a primary key in a database. Hex is generally friendlier on the eyes than a number alone.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public static string ToHexString(this int val){   return string.Format(&quot;{0:x2}&quot;, val);}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;FromHexString&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Likewise, when you have a hex encoded integer, it&#39;s quite useful to get that value back out. I have no idea why, but I forget this neat trick all the time and constantly have to look it up. No more!&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public static int FromHexString(this string val){   return Convert.ToInt32(val, 16);}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;ToUrlString&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I &lt;a href=&quot;https://jdconley.com/blog/clean-up-string-for-url&quot;&gt;posted this&lt;/a&gt; a few weeks ago. I love it...&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;GetRootPath&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This is something I have struggled with since the early days of ASP. There has never been a straightforward way to get the root of the URI of a request. This method extends HttpRequest and gives you the scheme (http/https) and host/port of the request. So, provided a request to http://jdconley.com/blog/ this extension would return http://jdconley.com&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public static string GetRootPath(this HttpRequest r){   string hostPort = r.Url.Authority;   string scheme = r.Url.Scheme;   string path = string.Concat(scheme, @&quot;://&quot;, hostPort);   return path;}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;GetConfigBasedPath&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A common task in a web app is to send out an email for one reason or another. Maybe you want to send someone a link to a download, confirm their registration, or bug them when they haven&#39;t visited your site in a while. This method takes an application relative path stored in your App.Config appSettings and translates it into a fully qualified URL based on the current executing page. Your configuration might look like:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;add key=&quot;EventDetailsFormatString&quot; value=&quot;~/events/{0}.aspx&quot;/&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You could then use the following extension to turn that relative URL into a fully qualified based on the current page that is executing. It relies on the GetRootPath method above.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public static string GetConfigBasedPath(   this Page p,   string configKey,   params object[] formatArgs){   if (null == p)       throw new ArgumentNullException(&quot;p&quot;);   if (string.IsNullOrEmpty(configKey))       throw new ArgumentNullException(&quot;configKey&quot;);   string valFromConfig = ConfigurationManager.AppSettings.Get(configKey);   if (null == valFromConfig)       throw new ArgumentOutOfRangeException(&quot;configKey&quot;,           configKey,           &quot;The specified key was not found in the configuration.&quot;);   Uri rootUri = new Uri(p.Request.GetRootPath(), UriKind.Absolute);   Uri relativeUri = new Uri(       p.ResolveUrl(string.Format(valFromConfig, formatArgs)),       UriKind.Relative);   Uri fullUri = new Uri(rootUri, relativeUri);   return fullUri.ToString();}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;IsDescendentOrSelfSelected&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In a Treeview you often want to see if a node or any of its children are selected to help determine how to display the tree. This is especially useful when using the Treeview for navigation.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public static bool IsDescendantOrSelfSelected(this TreeNode node){   if (node.Selected)   {       return true;   }   else if (node.ChildNodes.Count &amp;gt; 0)   {       foreach (TreeNode n in node.ChildNodes)       {           if (IsDescendantOrSelfSelected(n))               return true;       }       return false;   }   else     {         return false;   }}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;EnsureVisible&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This one is quite simple. It just makes sure that the provided node is visible in the tree by making sure all of its parent nodes are expanded. This is a useful function for stateless Treeviews or synchronizing the same Treeview across multiple pages.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public static void EnsureVisible(this TreeNode node){   if (null != node.Parent)   {       node.Parent.Expand();       EnsureVisible(node.Parent);   }}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Well, that&#39;s it for now! I hope someone finds these as useful as I do.&lt;/p&gt;
</content:encoded><category>.net</category><category>asp.net</category><category>utility</category></item>
<item><title>List of Country Names</title><link>https://jdconley.com/blog/list-of-country-names</link><guid isPermaLink="false">tag:blogger.com,1999:blog-1741199026308686058.post-554861436859257643</guid><pubDate>Wed, 05 Sep 2007 18:22:00 GMT</pubDate><description>Today I had to build yet-another-list of country names for a web site drop down form. I did some Google searching for about 10 minutes and didn&#39;t find anything that was free. I…</description><content:encoded>&lt;p&gt;Today I had to build yet-another-list of country names for a web site drop down form. I did some Google searching for about 10 minutes and didn&#39;t find anything that was free. I dunno, maybe I&#39;m just blind... I did, however, find a list on Wikipedia. So, I decided I&#39;d pull it down and parse it up. Here&#39;s the code:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;static void Main(string[] args){   string fullpage;   using (WebClient wc = new WebClient())   {       byte[] pageBytes = wc.DownloadData(           @&quot;http://en.wikipedia.org/wiki/List_of_country_name_etymologies&quot;);       string encoding = wc.ResponseHeaders[&quot;Content-Encoding&quot;];       fullpage = wc.Encoding.GetString(pageBytes);   }   MatchCollection countryMatches = Regex.Matches(fullpage,       @&quot;&amp;lt;p&amp;gt;&amp;lt;b&amp;gt;&amp;lt;a href=&quot;&quot;. &quot;&quot;\s*title=&quot;&quot;. &quot;&quot;&amp;gt;(?&amp;lt;country&amp;gt;. )&amp;lt;/a&amp;gt;&amp;lt;/b&amp;gt;:&amp;lt;/p&amp;gt;&quot;,       RegexOptions.Multiline);   foreach (Match m in countryMatches)   {       Group g = m.Groups[&quot;country&quot;];       Console.WriteLine(g.Value);   }   Console.WriteLine(&quot;done&quot;);   Console.ReadLine();}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see it&#39;s dirt simple. Just a WebClient to download the page (holy crap it&#39;s big) and a simple Regex call. Presto! A list of countries I&#39;ll be dropping into a database so we can edit it later.&lt;/p&gt;
</content:encoded><category>.net</category><category>random</category><category>utility</category></item>
<item><title>Don&#39;t forget to close your Linq to Sql connections</title><link>https://jdconley.com/blog/dont-forget-to-close-your-linq-to-sql</link><guid isPermaLink="false">tag:blogger.com,1999:blog-1741199026308686058.post-2521490268521831687</guid><pubDate>Thu, 30 Aug 2007 20:51:00 GMT</pubDate><description>Today I was working on some Linq to Sql code that dealt with an event management system. There are events people can attend, and attendees fill out a form to register for the…</description><content:encoded>&lt;p&gt;Today I was working on some Linq to Sql code that dealt with an event management system. There are events people can attend, and attendees fill out a form to register for the event. The fields for each event are configurable by the person that creates the event. When I save a set of event fields I want to do it in a transaction so I don&#39;t end up with a partial &quot;record&quot;. Here&#39;s what my code looked like originally:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public void SaveEventAttendeeFields(EventAttendeeField[] fields){   using (LinqToSqlDataContext dc = new LinqToSqlDataContext())   {       dc.DeferredLoadingEnabled = false;       try         {             dc.Connection.Open();             dc.Transaction = dc.Connection.BeginTransaction();              foreach (EventAttendeeField f in fields)           {               if (f.EventAddendeeFieldId &amp;gt; 0)                   dc.EventAttendeeFields.Attach(f, true);               else                     dc.EventAttendeeFields.Add(f);             }              dc.SubmitChanges();             dc.Transaction.Commit();         }         catch         {             if (null != dc.Transaction)               dc.Transaction.Rollback();           throw;       }   }}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I assumed this was perfectly fine, until I ran it through my unit test library. My test library automatically creates a new database, tables, sprocs, and then populates it with seed test data. At the end of the test run it drops the database that was created. Well, the drop was failing because the database was in use! I thought &quot;hmm, I wonder if my connections aren&#39;t being closed.&quot; Sure enough, if you manually open the connection in the DataContext you had better manually close it as well!&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public void SaveEventAttendeeFields(EventAttendeeField[] fields){   using (LinqToSqlDataContext dc = new LinqToSqlDataContext())   {       dc.DeferredLoadingEnabled = false;       try         {             dc.Connection.Open();             dc.Transaction = dc.Connection.BeginTransaction();              foreach (EventAttendeeField f in fields)           {               if (f.EventAddendeeFieldId &amp;gt; 0)                   dc.EventAttendeeFields.Attach(f, true);               else                     dc.EventAttendeeFields.Add(f);             }              dc.SubmitChanges();             dc.Transaction.Commit();         }         finally         {             if (null != dc.Connection &amp;amp;&amp;amp; dc.Connection.State != System.Data.ConnectionState.Closed)               dc.Connection.Close();       }   }}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This code didn&#39;t cause any leaks. So, moral of the story, close your connections in your DataContext if you open them.&lt;/p&gt;
</content:encoded><category>.net</category><category>linq</category></item>
<item><title>Clean Up a String for a Url</title><link>https://jdconley.com/blog/clean-up-string-for-url</link><guid isPermaLink="false">tag:blogger.com,1999:blog-1741199026308686058.post-3636100427201199919</guid><pubDate>Tue, 28 Aug 2007 16:54:00 GMT</pubDate><description>This is a quickie. Yesterday I was doing some Url rewriting for a project and accepting user input for said Url. It&#39;s basically like this blog system. I can specify the…</description><content:encoded>&lt;p&gt;This is a quickie. Yesterday I was doing some Url rewriting for a project and accepting user input for said Url. It&#39;s basically like this blog system. I can specify the friendly url of each post. So, I wrote a little extension method to clean up a string and make it URL friendly. Yes, you can just escape everything someone enters, but it&#39;s much friendlier to just make it work. Be lenient in what you accept! Here it is:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public static string ToUrlString(this string s){   if (null == s)       throw new NullReferenceException();     string tmp = Regex.Replace(s.ToLower(), @&quot;\s&quot;, @&quot;-&quot;);   tmp = Regex.Replace(tmp, @&quot;[^-_\.\w]&quot;, @&quot;&quot;);   return tmp;}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This simply replaces all whitespace with a &quot;-&quot;, and all characters that are not &quot;-&quot;, &quot;_&quot;, &quot;.&quot;, or Word Characters with an empty string.&lt;/p&gt;
&lt;p&gt;In the end, if your input is &quot;this is a @#)(*&amp;amp;*@$^ crock!&quot; you&#39;ll get &quot;this-is-a--crock&quot;. As a guy who was, at one time, scared of regular expressions I hope this helps someone.&lt;/p&gt;
</content:encoded><category>.net</category><category>asp.net</category></item>
<item><title>using (wcfclient) { } kaboom!</title><link>https://jdconley.com/blog/using-wcfclient-kaboom</link><guid isPermaLink="false">tag:blogger.com,1999:blog-1741199026308686058.post-4927664133002778517</guid><pubDate>Thu, 23 Aug 2007 05:20:00 GMT</pubDate><description>I&#39;ve been doing a lot of WCF development lately (love it) and ran into a bit of a stumbling block. The proxy client generated by Visual Studio 2008 Beta 2 doesn&#39;t handle fault…</description><content:encoded>&lt;p&gt;I&#39;ve been doing a lot of WCF development lately (love it) and ran into a bit of a stumbling block. The proxy client generated by Visual Studio 2008 Beta 2 doesn&#39;t handle fault conditions and dispose well. &lt;em&gt;I have to admit, I haven&#39;t used WCF in Visual Studio 2005.&lt;/em&gt; If you&#39;re impatient here&#39;s the project (Visual Studio 2008 Beta 2 project): &lt;a href=&quot;https://docs.google.com/viewer?a=v&amp;pid=explorer&amp;chrome=true&amp;srcid=0B7Ew2HKAAmajYmIwMzc0MDctYmZkNC00MzFkLWE2OTctZTUwMjU5MzQyMjAw&amp;hl=en_US&quot;&gt;wcfwrapper.zip&lt;/a&gt; The situation unfolds:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Problem - Dispose Isn&#39;t Safe!&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Create a WCF service.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[ServiceContract]public interface IGoodBadService{   [OperationContract]   void Good();   [OperationContract]   void Bad();}
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add a service reference to your service in another project.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create a service client and use it, with a &quot;using&quot; block (it is IDisposable, afterall).&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;try{   using (GoodBadServiceClient c =       new GoodBadServiceClient())   {       c.Bad();   }}catch (Exception ex){   Console.WriteLine(ex.Message);}
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A call to your service, for whatever reason, throws an exception.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public class GoodBadService   : IGoodBadService{   public void Good()   {       throw new Exception(&quot;GOOD!&quot;);   }   public void Bad()   {       throw new Exception(&quot;BAD!&quot;);   }}
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You get a cryptic System.ServiceModel.CommunicationObjectFaultedException instead of the real exception when using calls Dispose() on your proxy client. It reads: &lt;em&gt;The communication object, System.ServiceModel.Channels.ServiceChannel, cannot be used for communication because it is in the Faulted state.&lt;/em&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;The Solution - A Simple Generic Wrapper&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public class ServiceProxy&amp;lt;TClient&amp;gt;   : IDisposable   where TClient : ICommunicationObject{   public ServiceProxy(TClient client)   {       Client = client;   }   public TClient Client { get; private set; }   public void Dispose()   {       if (null != Client &amp;amp;&amp;amp;           Client.State != CommunicationState.Closed &amp;amp;&amp;amp;           Client.State != CommunicationState.Faulted)       {           Client.Close();       }   }}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Using the wrapper is pretty straightforward, but a tad more cryptic than just using the client directly. Some of this can be avoided with a generic factory.&lt;/p&gt;
&lt;p&gt;So, here&#39;s how you use it:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;try{   using (ServiceProxy&amp;lt;GoodBadServiceClient&amp;gt; c       = new ServiceProxy&amp;lt;GoodBadServiceClient&amp;gt;(           new GoodBadServiceClient()))   {       c.Client.Good();   }}catch (Exception ex){   Console.WriteLine(ex.Message);}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Run the project and check out the results. The wrapper gives you the actual exception, whereas &quot;using&quot; the client directly causes the CommunicationObjectFaultedException. Here&#39;s the project (Visual Studio 2008 Beta 2 project): &lt;a href=&quot;https://docs.google.com/viewer?a=v&amp;pid=explorer&amp;chrome=true&amp;srcid=0B7Ew2HKAAmajYmIwMzc0MDctYmZkNC00MzFkLWE2OTctZTUwMjU5MzQyMjAw&amp;hl=en_US&quot;&gt;wcfwrapper.zip&lt;/a&gt;&lt;/p&gt;
</content:encoded><category>wcf</category></item>
<item><title>Relocation</title><link>https://jdconley.com/blog/relocation</link><guid isPermaLink="false">tag:blogger.com,1999:blog-1741199026308686058.post-3800237020780798768</guid><pubDate>Wed, 22 Aug 2007 06:37:00 GMT</pubDate><description>Well, I&#39;ve officially relocated my blog here, to jdconley.com. The old blogging engine I was using really sucked. This one seems a lot better. And if I don&#39;t like something,…</description><content:encoded>&lt;p&gt;Well, I&#39;ve officially relocated my blog here, to &lt;a href=&quot;http://jdconley.com/&quot;&gt;jdconley.com&lt;/a&gt;. The old blogging engine I was using really sucked. &lt;a href=&quot;http://www.subtextproject.com/&quot;&gt;This one&lt;/a&gt; seems a lot better. And if I don&#39;t like something, the source code looks pretty clean so I can get my hands dirty and change it. I&#39;m also a fan of one of the &lt;a href=&quot;http://haacked.com/&quot;&gt;Haack&lt;/a&gt;s that wrote it -- well, his blog at least.&lt;/p&gt;
&lt;p&gt;In addition to a new blog engine my new location has implicitly granted me a little freedom. Fear not, my blog will no longer be 100% about Coversant related items. I&#39;ve been exploring the wide world of .NET 3.5, Visual Studio 2008, and everything in between. I&#39;ve got a few articles that need some polish and I&#39;ll be posting them here.&lt;/p&gt;
</content:encoded><category>random</category></item>
<item><title>Friend Photosaver for Facebook</title><link>https://jdconley.com/blog/friend-photosaver-for-facebook</link><guid isPermaLink="false">tag:blogger.com,1999:blog-1741199026308686058.post-1477714049596343834</guid><pubDate>Thu, 21 Jun 2007 00:26:00 GMT</pubDate><description>By now everybody who knows what Facebook is, knows they announced an open platform for integrating with it. Interestingly enough Microsoft was a launch partner of theirs so…</description><content:encoded>&lt;p&gt;By now everybody who knows what &lt;a href=&quot;http://www.facebook.com/&quot;&gt;Facebook&lt;/a&gt; is, knows they announced &lt;a href=&quot;http://developers.facebook.com/&quot;&gt;an open platform&lt;/a&gt; for integrating with it. Interestingly enough Microsoft was a launch partner of theirs so there is also a shared source .NET API layer available. We decided to jump on the opportunity and published &lt;a href=&quot;http://soapbox.net/facebook.aspx&quot;&gt;SoapBox for Facebook&lt;/a&gt;. Chris mentioned this in his &lt;a href=&quot;http://www.coversant.com/Coversant/Blogs/tabid/88/EntryID/43/Default.aspx&quot;&gt;announcement blog&lt;/a&gt; earlier.&lt;/p&gt;
&lt;p&gt;But, as with anything that goes to production, adding cool features quickly turned into fixing uncool bugs, scope discussions, planning sessions, and then it became work.&lt;/p&gt;
&lt;p&gt;I had a bit of a realization yesterday. I hadn&#39;t written code for the sheer fun of it in a really long time. Don&#39;t get me wrong, I love the stuff I do (almost) every day. We&#39;re coding cutting edge stuff here and it&#39;s a blast. But, I wanted to do something for me! So I wrote a screensaver.&lt;/p&gt;
&lt;p&gt;Strange, huh? The guy that writes blogs on memory management, async programming, and other maddening things decided to hack together a screensaver. You&#39;ll just have to get over the shock of it all... Research was done, scope was decided, fingers flew. A few hours later, I had a screensaver! At 2am I decided on its name (probably a bad idea), &lt;a href=&quot;http://www.facebook.com/apps/application.php?id=2466327790&quot;&gt;Friend Photosaver for Facebook&lt;/a&gt;, whipped up an installer and submitted the app to Facebook. Catchy isn&#39;t it? Yeeeah. Anyway, though the name stinks, I think it&#39;s a pretty cool screensaver.&lt;/p&gt;
&lt;p&gt;It aggregates the list of all your photos with all of the photos of your friends, and picks them at random. It then stuffs the photo in a random spot on the screen where it will be visible. Right now it only displays on the primary screen. Secondary screens are blank. Here&#39;s a little preview:&lt;/p&gt;
&lt;p&gt;Image unavailable: Screen Saver (&lt;a href=&quot;http://photos-c.ak.facebook.com/photos-ak-sctm/v43/1/718761709/app3_718761709_2466327790_7506.gif&quot;&gt;original source&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;If you&#39;re a Facebook user you can login and &lt;a href=&quot;http://www.facebook.com/apps/application.php?id=2466327790&quot;&gt;install my screensaver&lt;/a&gt;. The rest of you... well, this is pretty useless. But you should be on Facebook too. Oh, and (shameless plug), don&#39;t forget to use &lt;a href=&quot;http://soapbox.net/facebook.aspx&quot;&gt;SoapBox for Facebook&lt;/a&gt;. :)&lt;/p&gt;
</content:encoded><category>facebook</category><category>random</category><category>winforms</category></item>
<item><title>Simpler isn&#39;t always better - AsyncOperationsManager</title><link>https://jdconley.com/blog/simpler-isnt-always-better</link><guid isPermaLink="false">tag:blogger.com,1999:blog-1741199026308686058.post-4159598516278882360</guid><pubDate>Fri, 08 Jun 2007 18:51:00 GMT</pubDate><description>AsyncOperationManager... die! We have a new invitation system coming out soon for SoapBox Communicator and I was doing a little premature optimization, err, I mean, capacity…</description><content:encoded>&lt;p&gt;AsyncOperationManager... die!&lt;/p&gt;
&lt;p&gt;We have a new invitation system coming out soon for &lt;a href=&quot;http://soapbox.net/&quot;&gt;SoapBox Communicator&lt;/a&gt; and I was doing a little premature optimization, err, I mean, capacity planning. :) I set about to perform the simple task (or so I thought) of sending all of our email based invitations asynchronously. The architecture of the system is pretty simple. We have an ASP.NET 2.0 web site that you use inside SoapBox for sending invitations to your friends. The web site talks to an internal web service. The web service talks to a database. It&#39;s a pretty classic nTier design, with one exception. All layers are asynchronous.&lt;/p&gt;
&lt;p&gt;The UI uses asynchronous ASP.NET pages and &lt;a href=&quot;http://msdn2.microsoft.com/en-us/library/system.web.ui.page.registerasynctask.aspx&quot;&gt;RegisterAsyncTask&lt;/a&gt; to make the call to the EnqueueEmailInvites web service. The web service uses &lt;a href=&quot;https://msdn2.microsoft.com/en-us/library/aa480516.aspx&quot;&gt;asynchronous web methods&lt;/a&gt; and reads from/writes to our database using the &lt;a href=&quot;http://www.csharphelp.com/archives4/archive640.html&quot;&gt;asynchronous data methods&lt;/a&gt; in SqlClient.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Async Web Method&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;     [WebMethod]     public IAsyncResult BeginEnqueueEmailInvites(EmailInvitation invite, AsyncCallback callback, object state)     {         return InvitationFactory.BeginEnqueueEmailInvites(invite, callback, state);     }     [WebMethod]     public string[] EndEnqueueEmailInvites(IAsyncResult ar)     {         return InvitationFactory.EndEnqueueEmailInvites(ar);     }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Factory Calling DAL&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public static IAsyncResult BeginEnqueueEmailInvites(EmailInvitation invite, AsyncCallback callback, object state)        {            InviteEmailAsyncState myAs = new InviteEmailAsyncState();            myAs.Invitation = invite;            InviteEmailAsyncResult myAR = new InviteEmailAsyncResult(myAs, callback, state);            int emailInviteId = invite.Mutual ? GetInvitationTypeId(Constants.InviteTypeEmailMutual) : GetInvitationTypeId(Constants.InviteTypeEmail);            string csvAddresses = string.Join(&quot;,&quot;, new List&amp;lt;string&amp;gt;(invite.Addresses).ToArray());            Data.Invitations.BeginCreateReadInvitation(emailInviteId, invite.FromJid, invite.FromName, invite.Subject, invite.UserBodyPlain, string.Empty, csvAddresses, EmailInvitationCreatedCallback, myAR);            return myAR;        }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I write a lot of asynchronous code. A lot. I&#39;m a bit of an asynchronous I/O zealot. In fact, I&#39;ve had an article on the shelf called &quot;Asyncify your code&quot; for months now. l I just haven&#39;t got the sample code written for it yet. Anyway, my experience has led me to a simple conclusion: I hate the &lt;a href=&quot;http://msdn2.microsoft.com/en-us/library/system.componentmodel.asyncoperationmanager.aspx&quot;&gt;AsyncOperationManager&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Maybe it&#39;s because I write a lot of asynchronous code, or maybe just because people tend to &lt;a href=&quot;http://arstechnica.com/news.ars/post/20070605-product-loyalty-consumers-mistake-familiarity-with-superiority.html&quot;&gt;Mistake Familiarity with Superiority&lt;/a&gt;, but whatever the reasoning, I can&#39;t stand it. The AsyncOperationManager is used all over the .NET 2.0 framework where you see calls ending in &quot;Async&quot;, even though you probably don&#39;t even know it. One such instance that rubbed me the wrong way yesterday (and into this morning) is the &lt;a href=&quot;http://msdn2.microsoft.com/en-us/library/system.net.mail.smtpclient.aspx&quot;&gt;SmtpClient&lt;/a&gt;. Don&#39;t get me wrong, the SmtpClient is a great improvement over the old CDO based classes, but the Async support leaves something to be desired.&lt;/p&gt;
&lt;p&gt;First off, you can&#39;t call Send or SendAsync until the previous operation has completed. That means if you&#39;re sending out more than one email in succession you&#39;re going to need to do your own queueing. So I said to myself &quot;Ok, this is easy, I&#39;ll rip out the loop, register an eventhandler for SendCompleted, and pass a Queue through as state to SendAsync.&quot; This led me to the next problem.&lt;/p&gt;
&lt;p&gt;The asynchronous web method called the asynchronous data method, which led to a callback. Inside of this callback I grabbed some info from the data reader result and composed the MailMessage. I created a SmtpClient, registered for the SendCompleted event kicked off the first SendAsync, and completed the asynchronus web method. The mail sent great, but my SendCompleted event handler was never called.&lt;/p&gt;
&lt;p&gt;Apparently, if you make an async call there is the potential that the completed event handler you registered will never get called. Yep. You can call SendAsync, and the SendCompleted event will never be raised. I admit, the circumstances this happened in were kind of abnormal, but still. That just shouldn&#39;t happen.&lt;/p&gt;
&lt;p&gt;After a little reflectoring it was apparent this had something to do with the SynchronizationContext at the time of the call used by the AsyncOperationManager inside of the SmtpClient. I got a litte cross-eyed looking through the code in reflector so I gave up my hunt for the exact answer. My workaround: Call ThreadPool.QueueUserWorkItem and create the SmtpClient and call SendAsync inside of that callback. This gets you the generic SynchronizationContext that doesn&#39;t have anything weird associated with it, just plain ole async delegates. If someone has a better solution, please let me know.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Hack&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;             if (messagesToSend.Count &amp;gt; 0)             {                 //this seems strange, but we queue up the creation of the SmtpClient to a threadpool thread.                 //the synchronization context seems to become invalid when we complete the async web method call                                      //and we don&#39;t want to wait for the emails to go out to complete the web service call.                                      System.Threading.ThreadPool.QueueUserWorkItem(StartSendingEmailCallback, new object[] { myAr.MyAsyncState.Invitation, messagesToSend });             }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I have a plea to all framework designers out there. Have the decency to give me the good ole IAsyncResult based async pattern without all that extra AsyncOperationManager baggage! I don&#39;t want to have to worry about all that. I&#39;m a big boy. I can handle my own synchronization, and I like it that way.&lt;/p&gt;
</content:encoded><category>asp.net</category><category>async</category></item>
<item><title>XMPP Presence Priority</title><link>https://jdconley.com/blog/xmpp-presence-priority</link><guid isPermaLink="false">tag:blogger.com,1999:blog-1741199026308686058.post-2106830143411505646</guid><pubDate>Wed, 09 May 2007 02:02:00 GMT</pubDate><description>In XMPP (the messaging and presence protocol SoapBox uses) you can log in simultaneously on multiple systems. How your contat list is displayed and how messages are routed are…</description><content:encoded>&lt;p&gt;In XMPP (the messaging and presence protocol SoapBox uses) you can log in simultaneously on multiple systems. How your contat list is displayed and how messages are routed are based on hints the client software provides to the server. One of these is presence priority. Priority is just an integer value between -128 and 127 defined in &lt;a href=&quot;http://www.xmpp.org/rfcs/rfc3921.html#rfc.section.2.2.2.3&quot;&gt;RFC 3921 Section 2.2.2.3&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Managing priority is fairly straightforward when you control all client implementations used by a bare JID, but in a heterogeneous client environment it is more difficult as each developer chooses his/her own path and only learns by spying on what others do. I think presence priority is something that should be covered in the implementation guide so the actual values become more uniform on the network. We currently do pretty basic priority management, but I have some thoughts on a better implementation I hope others implementations might help refine.&lt;/p&gt;
&lt;p&gt;Priority is typically used by both clients and servers to determine which resource is most likely to be the one you want to interact with. This could be for routing messages sent to bare JID’s, or deciding which presence status to display in a contact list. So, after much deep thought and implementation trial/error, here is my proposal.&lt;/p&gt;
&lt;p&gt;Unless a user explicitly specifies she does not want to receive any messages, never set the priority below 0.&lt;/p&gt;
&lt;p&gt;In desktop software, presence priority is based first on user input activity. It is more likely that if a user is active, she will be there to respond to a message, regardless of the presence status that is set in the client software. The actual times may vary based on implementation, but the general idea is to have four base values:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;User input idle less than 1 minute: 100&lt;/li&gt;
&lt;li&gt;User input idle more than 1 minute: 80&lt;/li&gt;
&lt;li&gt;User input idle less than 5 minutes: 60&lt;/li&gt;
&lt;li&gt;User input idle less than 30 minutes: 40&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When these idle thresholds are met, presence should be broadcast. The current &lt;a href=&quot;http://www.xmpp.org/rfcs/rfc3921.html#rfc.section.2.2.2.1&quot;&gt;show value&lt;/a&gt; is then applied.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;chat: -4&lt;/li&gt;
&lt;li&gt;none (normal/available): -4&lt;/li&gt;
&lt;li&gt;dnd: -4&lt;/li&gt;
&lt;li&gt;away: -8&lt;/li&gt;
&lt;li&gt;xa: -12&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Thus, if a user has been idle for more than 30 minutes and has a show of xa, her priority is 28 (40-12). If a user has been idle for more than 30 minutes and has a show of away her priority is 32 (40-8). By starting at a high number and leaving padding between each show value, we leave room for implementations to add additional rules to adjust priority. Dnd has a higher priority than away and xa because, although the user does not want to be disturbed they are more likely to be at the dnd resource than the away or xa resource. It is up to the client implementation to insure they are not disturbed per the user’s configuration. A show of dnd uses the same priority as none and chat since you are likely equally available, you just don’t want to be disturbed.&lt;/p&gt;
&lt;p&gt;Priority and, optionally, show values are adjusted automatically based on common “away from the computer” events: system input idleness (how long since the user interacted with the system), when a session is locked, or a session screen saver is active. When these events occur, the priority rules must be processed again. For Example, my client is configured to go to a show of away after 5 minutes with a status of “AFK”. After 30 minutes it is set to a show value of xa and a status of “AFK for a long time”. When my system is locked or the screen saver comes on, my client automatically adjusts my show value to away and a status of “Not here”. Important: even if an implementation does not change status messages or show values after these “away from the computer” events it must still adjust its priority as defined above.&lt;/p&gt;
&lt;p&gt;After the “away from the computer” rules are processed, the relative availability of your peer resources is taken into account. If any peer was more recently more available (had a more available show value than your current value – chat, none/dnd, away, then xa) and has a non-negative priority, subtract 20 from your current priority. For example: I’m logged in at home and work. At home I last announced available presence 4 hours ago. My software at home never puts me into “xa” and instead decides I am “away” after 30 minutes. Home priority is now 32 (40-8). At work I last announced available presence 3 hours ago with a “none” show value. I go to lunch at work but it is configured to reach a show value of xa after 30 minutes. Its priority is now 28 (40-12). However, since work was my last active resource, when my home resource receives the broadcast from work it adjusts itself to a presence priority of 12 (32-20). The purpose of this is to insure that only the most recently available resource above more available than away/xa is the one that takes the higher priority.&lt;/p&gt;
&lt;p&gt;It is important to never adjust your priority relative to the priority of a peer resource without taking much care. Doing so can cause a “race” for the highest or lowest priority (depending on the relative direction your adjusting).&lt;/p&gt;
&lt;p&gt;That&#39;s about it. I also posted this on the XMPP standards mailing list. Reaching a concensus on how to adjust presence priority sure will help user perception of XMPP software.&lt;/p&gt;
</content:encoded><category>xmpp</category></item>
<item><title>Building Reactive User Interfaces in .NET: ISynchronizeInvoke on Idle Time</title><link>https://jdconley.com/blog/building-reactive-user-interfaces-in</link><guid isPermaLink="false">tag:blogger.com,1999:blog-1741199026308686058.post-5839251310447380729</guid><pubDate>Wed, 11 Apr 2007 03:55:00 GMT</pubDate><description>One of the most common things to do in a multi-threaded .NET Windows Forms application is to use the ISynchronizeInvoke interface on a Control to marshal things into the UI…</description><content:encoded>&lt;p&gt;One of the most common things to do in a multi-threaded .NET Windows Forms application is to use the &lt;a href=&quot;http://msdn2.microsoft.com/en-us/library/system.componentmodel.isynchronizeinvoke.aspx&quot;&gt;ISynchronizeInvoke interface&lt;/a&gt; on &lt;a href=&quot;http://www.interact-sw.co.uk/iangblog/2004/08/17/badsynclocking&quot;&gt;a Control&lt;/a&gt; to marshal things into the UI thread. The basic jist of things is: you can have the Windows Forms engine call your delegate on the thread that created the Control instance you&#39;re using. It does this using the window message pump. Typical uses of the ISynchronizeInvoke are: you want to read some data from a file, database, socket, or web service and you want your application to be responsive while you do it. When you&#39;re done you do a BeginInvoke/Invoke on the Control to update some UI elements. Well, sometimes using a Control&#39;s ISynchronizeInvoke leads to hung GUI&#39;s.&lt;/p&gt;
&lt;p&gt;If you have a lot of asynchronous operations pending and they complete in bunches the affect on your UI can be the appearance of a hang or sluggishness as drawing is queued behind the delegates you registered with BeginInvoke on your control. During the login sequeunce in &lt;a href=&quot;http://www.coversant.com/products/communicator/overview.aspx&quot;&gt;SoapBox Communicator&lt;/a&gt; there are potentially thousands of events that need to be processed on the UI thread. Yup, thousands. Your roster arrives from the server. You receive the current avialability from every online person on your roster. You got 10 messages while you were offline. Each of your contact&#39;s cached profiles (avatars, names, client capabilities, etc) are read from disk and compared with the user&#39;s current presence. This onslought of activity can be handled a number of ways. The basic principles I stumbled into after much trial and error is:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Never, ever, ever, ever, ever do IO on a UI thread. Even something as simple as reading a 1KB image from disk can bring your UI to a halt under the right circumstances.&lt;/li&gt;
&lt;li&gt;Use timers and update common pieces of UI (like list views) in batches whose changes were caused changes by background operations. This will reduce flicker as you invalidate areas to redraw.&lt;/li&gt;
&lt;li&gt;Use &lt;a href=&quot;http://www.informit.com/guides/content.asp?g=dotnet&amp;seqNum=486&amp;rl=1&quot;&gt;Application.Idle&lt;/a&gt; to your advantage. (see my take on this below)&lt;/li&gt;
&lt;li&gt;Be careful how many window handles you create. Controls are useful, but sometimes you&#39;ve just gotta draw your own.&lt;/li&gt;
&lt;li&gt;Profile your code where it seems sluggish.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I mentioned above that you should use Application.Idle to your advantage. The articles I&#39;ve found on it all mention coding precise things you want to do in that event, like updating a single form. I wanted to do it more generically. So, I created an implementation of ISynchronizeInvoke that uses the &lt;a href=&quot;http://msdn2.microsoft.com/en-us/library/system.windows.forms.application.idle.aspx&quot;&gt;Application.Idle event&lt;/a&gt; to process qeued items. I&#39;ve created a (only slightly) contrived example that uses a &lt;a href=&quot;http://www.personalmicrocosms.com/pages/cspc_samples_pi.aspx&quot;&gt;Pi Calculator&lt;/a&gt; I found and an animated Gif to demonstrate a hanging GUI.&lt;/p&gt;
&lt;p&gt;&lt;a id=&quot;BLOGGER_PHOTO_ID_5635022983022101410&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://jdconley.com/blog-assets/imported/2b8ff899c303642584ed16e6.png&quot;&gt;&lt;img src=&quot;https://jdconley.com/blog-assets/imported/2b8ff899c303642584ed16e6.png&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Both buttons calculate Pi to 50 digits on the UI thread using 100 separate ISynchronizeInvoke.BeginInvoke calls. The &quot;Idle Invoke&quot; button does so using my &lt;a href=&quot;https://docs.google.com/viewer?a=v&amp;pid=explorer&amp;chrome=true&amp;srcid=0B7Ew2HKAAmajMTkxY2NmMWQtZWE3ZS00MDdkLWE5NGUtZTA3YjUyY2JiMGEz&amp;hl=en_US&quot;&gt;ApplicationIdleSynchronizer&lt;/a&gt;. The &quot;Direct Invoke&quot; button calls BeginInvoke on the Form directly. You can click the buttons any number of times and more and more Pi calculation runs will be queued. The completed label is incremented after every run. Here&#39;s the code:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    public partial class Form1 : Form {     private const int WorkItems = 100;     private const int PiDigitsToCalc = 50;     private int _workItemsCompleted = 0;     private ApplicationIdleSynchronizer _idleSynchronizer = new ApplicationIdleSynchronizer();     public Form1()     {         InitializeComponent();     }     protected override void OnClosed(EventArgs e)     {         base.OnClosed(e);         _idleSynchronizer.Dispose();     }     private void button1_Click(object sender, EventArgs e)     {         System.Threading.ThreadPool.QueueUserWorkItem(QueueOnBackgroundThread, _idleSynchronizer);     }     private void button2_Click(object sender, EventArgs e)     {         System.Threading.ThreadPool.QueueUserWorkItem(QueueOnBackgroundThread, this);     }     private void QueueOnBackgroundThread(object state)     {         for (int i = 0; i &amp;lt; WorkItems; i  )         {             ((ISynchronizeInvoke)state).BeginInvoke(new ThreadStart(MyWorkItem), null);         }     }     private void MyWorkItem()     {         PiCalculator.CalculatePi(PiDigitsToCalc);         _workItemsCompleted++;         label2.Text = _workItemsCompleted.ToString();     } }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Click the buttons. Move the form around. Resize it. You might be suprised by the result (or not). Both very adequately use your CPU, but the Idle Invoke produces a much more reactive UI. You can download the full source code here: &lt;a href=&quot;https://docs.google.com/viewer?a=v&amp;pid=explorer&amp;chrome=true&amp;srcid=0B7Ew2HKAAmajMTkxY2NmMWQtZWE3ZS00MDdkLWE5NGUtZTA3YjUyY2JiMGEz&amp;hl=en_US&quot;&gt;ApplicationIdleInvoker.zip&lt;/a&gt;. Note, this exact code isn&#39;t in use in production. I wrote it for this blog. YMMV. Let me know if it has any issues.&lt;/p&gt;
</content:encoded><category>tuning</category><category>winforms</category></item>
<item><title>YouTube Getter</title><link>https://jdconley.com/blog/youtube-getter</link><guid isPermaLink="false">tag:blogger.com,1999:blog-1741199026308686058.post-6469503447914068558</guid><pubDate>Fri, 06 Apr 2007 01:13:00 GMT</pubDate><description>Usually everything I post here is serious business. Well, not today! Today, we&#39;re going to look at how to get the raw video stream for YouTube videos. Why, you ask? Well,…</description><content:encoded>&lt;p&gt;Usually everything I post here is serious business. Well, not today! Today, we&#39;re going to look at how to get the raw video stream for YouTube videos. Why, you ask? Well, curiosity, mostly. :) Some people like sports, I like problem solving. There are a number of browser plug-ins and web sites that do this already, but hey, it was still fun.&lt;/p&gt;
&lt;p&gt;YouTube offers a &lt;a href=&quot;http://www.youtube.com/dev&quot;&gt;bit of an API&lt;/a&gt; for developers to mess with. It&#39;s mostly for grabbing sets of videos and preview images and such. They also let you embed their player in your pages. That&#39;s awfully nice of them, but what if I don&#39;t like their player? What if I want a sexier player? Well, if you&#39;ve got something that can play/convert Flash Video (FLV&#39;s), here&#39;s the full C# code to grab the FLV URI (pieces dissected below):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;using System;using System.Collections.Generic;using System.Text;using System.Net;using System.IO;using System.Web;using System.Collections.Specialized;namespace JDFun{  public static class YouTubeGetter  {      public static Uri GetFlvUri(string viewUri)      {          return GetFlvUri(new Uri(viewUri));      }      public static Uri GetWatchUri(Uri flvUri)      {          NameValueCollection qry = HttpUtility.ParseQueryString(flvUri.Query);          string videoID = qry[&quot;video_id&quot;];          string watchUri = string.Concat(&quot;http://www.youtube.com/watch?v=&quot;, HttpUtility.UrlEncode(videoID));          return new Uri(watchUri);      }      public static Uri GetImageUri(Uri flvUri)      {          NameValueCollection qry = HttpUtility.ParseQueryString(flvUri.Query);          string imageUri = qry[&quot;iurl&quot;];          return new Uri(imageUri);      }      public static Uri GetFlvUri(Uri viewUri)      {          // so either i&#39;ve got the embed link or the watch link          //watch link: http://www.youtube.com/watch?v=up-RX_YN7yA          //embed link: http://www.youtube.com/v/up-RX_YN7yA          string toQuery = null;          NameValueCollection queryString = HttpUtility.ParseQueryString(viewUri.Query);          string videoId = queryString[&quot;v&quot;];          if (null != videoId)          {              toQuery = string.Concat(&quot;http://www.youtube.com/v/&quot;, videoId);          }          else          {              toQuery = viewUri.ToString();          }          if (null == toQuery)              throw new InvalidOperationException(&quot;Not a valid YouTube Uri.&quot;);          Uri queryUri = new Uri(toQuery);          //ok we have the uri to query, now go there and get redirected.          HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(queryUri);          req.AllowAutoRedirect = true;          // make them think we&#39;re coming from a direct link          req.Referer = string.Empty;          // firefox rules!          req.UserAgent = &quot;Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.8.1.3) Gecko/20070309 Firefox/2.0.0.3&quot;;          using (HttpWebResponse resp = (HttpWebResponse)req.GetResponse())          {              string absoluteRedirectLocation = resp.ResponseUri.AbsoluteUri;              //replace the swf with the get_video request              if (!absoluteRedirectLocation.Contains(&quot;/p.swf?&quot;))                  throw new InvalidOperationException(&quot;Unrecognized Uri. YouTube changed something.&quot;);              absoluteRedirectLocation = absoluteRedirectLocation.Replace(&quot;/p.swf?&quot;, &quot;/get_video?&quot;);              //return the absolute URI for this request              return new Uri(absoluteRedirectLocation);          }      }  }}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ok, wow, that&#39;s a lot bigger than I remember. Here&#39;s the basic idea.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Get the video ID from the given URI. The URI could be the &quot;watch&quot; URI, or it could be the URI from the embed code they give you.&lt;/li&gt;
&lt;li&gt;Load the video directly based on the video ID, at the embed URI.&lt;/li&gt;
&lt;li&gt;Make a HTTP Request and get redirected to another URI, (which happens to contain the Image URI, and a special token &quot;t&quot;).&lt;/li&gt;
&lt;li&gt;Know the magic URI where they keep the video streams (&lt;a href=&quot;http://www.methodshop.com/gadgets/tutorials/youtuberip/&quot;&gt;I cheated&lt;/a&gt;) and use it.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Now wasn&#39;t that fun? :)&lt;/p&gt;
</content:encoded><category>.net</category><category>random</category></item>
<item><title>Validating JabberID Nodes (XMPP/SoapBox User Names)</title><link>https://jdconley.com/blog/validating-jabberid-nodes-xmppsoapbox</link><guid isPermaLink="false">tag:blogger.com,1999:blog-1741199026308686058.post-2948995150946085884</guid><pubDate>Tue, 13 Mar 2007 17:48:00 GMT</pubDate><description>One of the most common, and tedious, tasks that comes up while writing software is validating user input. &quot;Don&#39;t trust the user,&quot; the mantra goes. Even with current development…</description><content:encoded>&lt;p&gt;One of the most common, and tedious, tasks that comes up while writing software is validating user input. &quot;Don&#39;t trust the user,&quot; the mantra goes. Even with current development tools it is still suprisingly difficult (i.e. not automatic) to validate user input and provide useful feedback to people who enter bad data.&lt;/p&gt;
&lt;p&gt;For the web (http/dhtml), ASP.Net provides the best implementation I&#39;ve seen so far. Controls like the &lt;a href=&quot;http://msdn2.microsoft.com/en-us/eahwtc9e.aspx&quot;&gt;RegularExpressionValidator&lt;/a&gt; combined with a &lt;a href=&quot;http://msdn2.microsoft.com/en-us/system.web.ui.webcontrols.validationsummary.aspx&quot;&gt;ValidationSummary&lt;/a&gt; or the more recent &lt;a href=&quot;http://ajax.asp.net/ajaxtoolkit/ValidatorCallout/ValidatorCallout.aspx&quot;&gt;Validator Callout&lt;/a&gt; allow you to create a very intuitive and reactive interface while still providing server side input validation. Well, how does all this apply to JabberID Nodes?&lt;/p&gt;
&lt;p&gt;A &lt;a href=&quot;http://www.xmpp.org/rfcs/rfc3920.html#addressing&quot;&gt;JabberID Node&lt;/a&gt; is essentially your user name on an XMPP domain. I am jconley@coversant.net, thus &quot;jconley&quot; is my JabberID Node. A JabberID is represented by the ABNF form: [ node &quot;@&quot; ] domain [ &quot;/&quot; resource ] (for more details see the &lt;a href=&quot;http://www.xmpp.org/rfcs/rfc3920.html#addressing&quot;&gt;Addressing Scheme&lt;/a&gt; section of &lt;a href=&quot;http://www.xmpp.org/rfcs/rfc3920.html&quot;&gt;RFC 3920&lt;/a&gt;). Now, as with any good RFC the exact definition of what is permitted is available. It&#39;s, long, it&#39;s complicated, it&#39;s (eek) Unicode, it&#39;s called StringPrep. To be more precise, the &lt;a href=&quot;http://www.xmpp.org/rfcs/rfc3920.html#nodeprep&quot;&gt;NodePrep Profile Prohibited Output&lt;/a&gt;. The domain and resource also have their own rules, but maybe we&#39;ll talk about that another day.&lt;/p&gt;
&lt;p&gt;Up until recently I haven&#39;t had to worry much about StringPrep. &lt;a href=&quot;http://www.blogger.com/www.coversant.com/blogs/cmullins.aspx&quot;&gt;Chris&lt;/a&gt; was the unlucky soul here to bite that one off, so he is officially our in-house Unicode geek. Way down deep in our coversant.corlib assembly of the SoapBox Framework there is a namespace called &quot;Coversant.StringPrep&quot;. This is automatically used by our JabberID class to make sure that JabberID&#39;s are always in the right format and do not contain any bad data. Well, this last week I had to build a web page that someone could enter JabberID Node information on. I wanted this to be, for the most part, handled on the client side to provide instant feedback and correction for common mistakes (like including a space), but still use the server for final validation (don&#39;t want those evil bots trying to mess with my page!).&lt;/p&gt;
&lt;p&gt;The most elegant way I could think of was to create a regular expression to validate the input. This would let me utilize the controls already in ASP.Net for client and server side validation. As it turns out this isn&#39;t straighforward. From what I could figure out, the Regex engine included with Microsoft.Net (and today&#39;s browsers) do not support unicode code points above 16bits. Nodeprep Prohibit says There are thousands of disallowed code points above there (it goes up to 32 bits).&lt;/p&gt;
&lt;p&gt;So, in the end, we validate as much as we can on the client with the following expression (I shamelessly stole the ASCII portions from &lt;a href=&quot;http://crucially.livejournal.com/&quot;&gt;Artur&lt;/a&gt; - a guy I met at the &lt;a href=&quot;http://www.coversant.com/Coversant/Blogs/tabid/88/EntryID/11/Default.aspx&quot;&gt;XMPP Interop Event&lt;/a&gt; last year): ^([\x29\x23-\x25\x28-\x2E\x30-\x39\x3B\x3D\x3F\x41-\x7E\xA0 \u1680\u202F\u205F\u3000\u2000-\u2009\u200A-\u200B\u06DD \u070F\u180E\u200C-\u200D\u2028-\u2029\u0080-\u009F \u2060-\u2063\u206A-\u206F\uFFF9-\uFFFC\uE000-\uF8FF\uFDD0-\uFDEF \uFFFE-\uFFFF\uD800-\uDFFF\uFFF9-\uFFFD\u2FF0-\u2FFB]{1,1023}) Oh, there are some artificial line breaks in that Regex. Don&#39;t include those. :) We leave the rest up to a &lt;a href=&quot;http://msdn2.microsoft.com/en-us/9eee01cx.aspx&quot;&gt;CustomValidator&lt;/a&gt; on the server side and the SoapBox JabberID.ValidateUserText method.&lt;/p&gt;
</content:encoded><category>asp.net</category><category>xmpp</category></item>
<item><title>Installing Coversant Products on Vista</title><link>https://jdconley.com/blog/installing-coversant-products-on-vista</link><guid isPermaLink="false">tag:blogger.com,1999:blog-1741199026308686058.post-1317392116403861647</guid><pubDate>Fri, 15 Dec 2006 02:32:00 GMT</pubDate><description>Due to the enhanced security in Windows Vista, not all Coversant products are able to be installed out of the box. Luckily, this is really easy to work around and rest assured,…</description><content:encoded>&lt;p&gt;Due to the enhanced security in Windows Vista, not all Coversant products are able to be installed out of the box. Luckily, this is really easy to work around and rest assured, future version of our installation packages will not suffer from these issues.&lt;/p&gt;
&lt;p&gt;The symptoms show up as an error message dialog with code 2869:&lt;/p&gt;
&lt;p&gt;&lt;a id=&quot;BLOGGER_PHOTO_ID_5632072683334427730&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://jdconley.com/blog-assets/imported/a9c4c1a675feb6b0ee6a9a0a.png&quot;&gt;&lt;img src=&quot;https://jdconley.com/blog-assets/imported/3baf51f18330d4a8c00233bd.png&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;And then a series of empty dialog boxes:&lt;/p&gt;
&lt;p&gt;&lt;a id=&quot;BLOGGER_PHOTO_ID_5632072928238738546&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://jdconley.com/blog-assets/imported/50a9d48773c9808962558f5d.png&quot;&gt;&lt;img src=&quot;https://jdconley.com/blog-assets/imported/5eae5111d928a1cc9d1f5544.png&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This is apparently some sort of permissions issue. To solve it, the MSI needs to be run as an administrator. The easiest way to do this is to create a bat file to run the msi manually. It would be something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;msiexec.exe /i &quot;c:\SoapBoxServer2007\files\SoapBox.Server.Enterprise.x64.3.0.213.69.msi&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then you right click on the bat file and choose &quot;Run As Administrator&quot;. Presto, a working installation in Vista.&lt;/p&gt;
</content:encoded><category>soapbox</category><category>windows</category></item>
<item><title>XSLT For MSDN Product Keys</title><link>https://jdconley.com/blog/xslt-for-msdn-product-keys</link><guid isPermaLink="false">tag:blogger.com,1999:blog-1741199026308686058.post-8638020826163728097</guid><pubDate>Tue, 21 Nov 2006 23:00:00 GMT</pubDate><description>Here at Coversant we&#39;re Microsoft partners. We have MSDN subscriptions for all our developers/testers, and we share the same set of license keys. Rather than give everyone…</description><content:encoded>&lt;p&gt;Here at Coversant we&#39;re Microsoft partners. We have MSDN subscriptions for all our developers/testers, and we share the same set of license keys. Rather than give everyone willy-nilly access to the MSDN download web site (ick, lots of bandwidth suck) we setup an internal file share for MSDN installation files, CD images, etc. We used to have all the product keys in there just saved as html from Microsoft&#39;s web site. However, that&#39;s no fun!&lt;/p&gt;
&lt;p&gt;In the spirit of having fun and being developer friendly, Microsoft is nice enough to offer an &quot;Export Key List to XML&quot; button on the web page where we view all our product keys. So, I clicked the button. Out popped a very nicely/simply formatted XML document, like the following:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;?xml version=&quot;1.0&quot; standalone=&quot;yes&quot;?&amp;gt;&amp;lt;Your_Product_Keys&amp;gt; &amp;lt;Product_Key  Name=&quot;All products requiring a 10-digit product key&quot;  Key=&quot;xxx-xxx-xxxx&quot;  Key_Type=&quot;Retail&quot;/&amp;gt; &amp;lt;Product_Key  Name=&quot;Windows Vista Ultimate&quot;  Key=&quot;XXXXX-XXXXX-XXXXX-XXXXX-XXXXX&quot;  Key_Type=&quot;Retail&quot;  Date_Key_Claimed=&quot;2006-11-20 17:36:11.787&quot;/&amp;gt; &amp;lt;Product_Key  Name=&quot;Windows Server 2003 R2 Standard Edition&quot;  Key=&quot;XXXXX-XXXXX-XXXXX-XXXXX-XXXXX&quot;  Key_Type=&quot;Retail&quot;  Date_Key_Claimed=&quot;2006-11-20 17:36:08.270&quot;/&amp;gt; &amp;lt;Product_Key  Name=&quot;Office 2007 Desktop Programs&quot;  Key=&quot;XXXXX-XXXXX-XXXXX-XXXXX-XXXXX&quot;  Key_Type=&quot;Retail&quot;  Date_Key_Claimed=&quot;2006-11-20 17:35:57.537&quot;/&amp;gt;  ...&amp;lt;/Your_Product_Keys&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I whipped up a quick XSLT you might find useful to transform this to a really ugly, really simple, x-html page (yeah without the namespace declaration).&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;ISO-8859-1&quot;?&amp;gt;&amp;lt;xsl:stylesheet version=&quot;1.0&quot;xmlns:xsl=&quot;http://www.w3.org/1999/XSL/Transform&quot;&amp;gt;&amp;lt;xsl:template match=&quot;/&quot;&amp;gt; &amp;lt;html&amp;gt; &amp;lt;body&amp;gt;   &amp;lt;h2&amp;gt;MSDN Product Keys&amp;lt;/h2&amp;gt;   &amp;lt;table border=&quot;1&quot;&amp;gt;   &amp;lt;tr bgcolor=&quot;#9acd32&quot;&amp;gt;     &amp;lt;th align=&quot;left&quot;&amp;gt;Product Name&amp;lt;/th&amp;gt;     &amp;lt;th align=&quot;left&quot;&amp;gt;Product Key&amp;lt;/th&amp;gt;   &amp;lt;/tr&amp;gt;   &amp;lt;xsl:for-each select=&quot;/Your_Product_Keys/Product_Key&quot;&amp;gt;   &amp;lt;tr&amp;gt;     &amp;lt;td&amp;gt;&amp;lt;xsl:value-of select=&quot;@Name&quot;/&amp;gt;&amp;lt;/td&amp;gt;     &amp;lt;td&amp;gt;&amp;lt;xsl:value-of select=&quot;@Key&quot;/&amp;gt;&amp;lt;/td&amp;gt;   &amp;lt;/tr&amp;gt;   &amp;lt;/xsl:for-each&amp;gt;   &amp;lt;/table&amp;gt; &amp;lt;/body&amp;gt; &amp;lt;/html&amp;gt;&amp;lt;/xsl:template&amp;gt;&amp;lt;/xsl:stylesheet&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then I made one quick edit to the xml file so friendly xslt aware web browsers will do the transform for me:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;?xml version=&quot;1.0&quot; standalone=&quot;yes&quot;?&amp;gt;&amp;lt;?xml-stylesheet type=&quot;text/xsl&quot; href=&quot;productkeys.xslt&quot;?&amp;gt;&amp;lt;Your_Product_Keys&amp;gt;  ...&amp;lt;/Your_Product_Keys&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Presto-chango, we now have an easy to update central listing of our MSDN keys. Now if only MS had a web service that took my Live ID credentials and gave me back that XML...&lt;/p&gt;
</content:encoded><category>random</category></item>
<item><title>Compact Framework WaitHandle.WaitOne Gotcha</title><link>https://jdconley.com/blog/compact-framework-waithandlewaitone</link><guid isPermaLink="false">tag:blogger.com,1999:blog-1741199026308686058.post-6288449040506861270</guid><pubDate>Wed, 08 Nov 2006 22:32:00 GMT</pubDate><description>I ran into a behavior in the 2.0 Compact Framework today that was most vexing. It wasn&#39;t hard to find like a subtle race condition. It wasn&#39;t an issue that only duplicated with…</description><content:encoded>&lt;p&gt;I ran into a behavior in the 2.0 Compact Framework today that was most vexing. It wasn&#39;t hard to find like a subtle race condition. It wasn&#39;t an issue that only duplicated with a certain system configuration, under a full moon, on Wednesday. No, it duplicated every single time the code was ran. But, it wasn&#39;t documented anywhere I could find.&lt;/p&gt;
&lt;p&gt;One of my favorite new features in the Compact Framework is the availability of the &lt;a href=&quot;http://msdn2.microsoft.com/en-us/library/kzy257t0.aspx&quot;&gt;WaitHandle.WaitOne&lt;/a&gt;(int, bool) overload. That&#39;s something we use quite a bit in our test code and here and there in the actual SoapBox Framework. We used to have our own ManualResetEvent implementation for the Compact Framework that P/Invoked out to Windows CE. But Micrsoft was nice enough to add this into the 2.0 Framework. Yay! (In case you never had the joy of programming to the .NET 1.0 framework, the only WaitOne overload that was there was the indefinitely blocking one. No timeouts allowed.)&lt;/p&gt;
&lt;p&gt;I was running our unit test suite against the Compact Framework and tests that used to pass until I ripped out our custom P/Invoking ManualResetEvent implementation were failing. Odd... Well, it turned out to be very easy to track down. &lt;a href=&quot;http://msdn2.microsoft.com/en-us/library/kzy257t0.aspx&quot;&gt;WaitHandle.WaitOne&lt;/a&gt;(int, true) throws an ArgumentException every single time. That&#39;s right. If you pass true to that second parameter, the exception is thrown.&lt;/p&gt;
&lt;p&gt;Don&#39;t get me wrong, I understand the implications of exiting the synchronization domain for the context or not. It turns out the code that was causing the error should have been passing &quot;false&quot; for the parameter anyway. But, why did the call throw an exception? Why not just ignore the argument when it&#39;s not relevant as the documentation alludes? And I quote from MSDN2: &quot;The exitContext parameter has no effect unless the WaitOne method is called from inside a nondefault managed context.&quot;&lt;/p&gt;
&lt;p&gt;Anyway, if you&#39;re doing any Compact Framework development, make sure to pass &quot;false&quot; into the exitContext parameter of your &lt;a href=&quot;http://msdn2.microsoft.com/en-us/library/kzy257t0.aspx&quot;&gt;WaitHandle.WaitOne&lt;/a&gt; calls.&lt;/p&gt;
</content:encoded><category>.net</category></item>
<item><title>The Catch with GoDaddy Dedicated Hosting</title><link>https://jdconley.com/blog/catch-with-godaddy-dedicated-hosting</link><guid isPermaLink="false">tag:blogger.com,1999:blog-1741199026308686058.post-4142246971923325819</guid><pubDate>Fri, 29 Sep 2006 18:40:00 GMT</pubDate><description>I&#39;m not known to get easily frustrated or publicly rant about something, but here goes. The public web site and soapbox.net IM service for Coversant is hosted with GoDaddy…</description><content:encoded>&lt;p&gt;I&#39;m not known to get easily frustrated or publicly rant about something, but here goes. The public web site and soapbox.net IM service for Coversant is hosted with &lt;a href=&quot;http://www.godaddy.com/&quot;&gt;GoDaddy&lt;/a&gt; using their &lt;a href=&quot;https://www.godaddy.com/gdshop/hosting/dedicated.asp?se=%2B&amp;ci=722&amp;display=dedicated&quot;&gt;dedicated server&lt;/a&gt; plans. This makes things real easy for us. We don&#39;t have to manage hardware somewhere in a colo. We get an ftp site for backups. And most of all we get the convenience and control of a dedicated system. It&#39;s also very reasonably priced. Ah, but there&#39;s always a catch.&lt;/p&gt;
&lt;p&gt;Some time near the end of last month our daily and hourly SQL Server backups went on a rampage. The hourly transaction log backup we have scheduled was stuck in a loop so it never reset itself. We were uploading the entire transaction log for the month every hour. The end result was a constant stream of uploading to our FTP backup site, which is hosted by GoDaddy as well. Oh, I should mention the FTP backup is a service we pay for monthly in addition to any dedicated server plan. Here comes the fun part. The bandwidth used to connect to our FTP backup site is charged at the normal rate as if you were serving up web pages to customers. If you go over your monthly allotment you get charged the burst bandwidth rate of $1.99/1000MB. Last month we went over 661 times, or roughly 661GB. You can do the multiplication there. I should mention a nice customer support rep discounted it 50% for us. I&#39;d really hate to have his job. . .&lt;/p&gt;
&lt;p&gt;While this isn&#39;t that much money in the scheme of things, it is really freaking annoying. It would have been nice to get a phone call letting us know the first time we went over, not when we got our monthly statement. And why do we have to pay for bandwidth to a service we pay for that&#39;s hosted by our hosting provider and is very likely even located in the same data center. Aaargh!&lt;/p&gt;
&lt;p&gt;So, in conclusion, we&#39;re researching what needs to be done to move to a local colo or perhaps another, slightly more expensive but not so unreasonable, dedicated hosting provider. Oh, we&#39;re still sorting out what caused the SQL backup issue.&lt;/p&gt;
</content:encoded><category>random</category></item>
<item><title>Gentoo Linux MAC Based Host Name</title><link>https://jdconley.com/blog/gentoo-linux-mac-based-host-name</link><guid isPermaLink="false">tag:blogger.com,1999:blog-1741199026308686058.post-7389091125871809749</guid><pubDate>Tue, 26 Sep 2006 01:22:00 GMT</pubDate><description>We use Gentoo for all our Linux development (yeah, we do Linux -- coming very very soon). In fact we are currently putting together a test lab with quite a few computers using…</description><content:encoded>&lt;p&gt;We use &lt;a href=&quot;http://www.gentoo.org/&quot;&gt;Gentoo&lt;/a&gt; for all our Linux development (yeah, we do Linux -- coming very very soon). In fact we are currently putting together a test lab with quite a few computers using Gentoo, &lt;a href=&quot;http://www.mono-project.com/&quot;&gt;Mono&lt;/a&gt;, and our own StressBot software to drive client load to our server.&lt;/p&gt;
&lt;p&gt;The lab currently consists of 25 computers, pointed at whatever server hardware/software configuration we happen to be testing. I&#39;ll post some pictures some day, I promise. As any IT guy will tell you, managing 25 computers isn&#39;t trivial. You have to make sure images stay in sync with the correct software builds, monitor that everything is working, etc. In a test lab this isn&#39;t so horrible, since our hardware is identical and we just use Ghost software and push out new images. However, this does bring up some interesting issues, the main one being the hostname. On Windows there are more issues, but we won&#39;t get into that.&lt;/p&gt;
&lt;p&gt;On your network the hostname uniquely identifies your system. If you&#39;re pushing out images, this gets a little hairy. Most organizations use some sort of boot script that contacts a central repository to take care of this. We didn&#39;t need that much control for our lab. Instead, we decided just to base the hostname on the MAC address of the primary NIC, a very simple and guaranteed unique mechanism. Since we&#39;re using Gentoo we have the /etc/conf.d/hostname file that is used at boot time to set the hostname. Here&#39;s what we used to set the hostname to contain the MAC address:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;lab0002A51B9F16 tmp # cat /etc/conf.d/hostname  # /etc/conf.d/hostname  # Set to lab+MAC (without &quot;:&quot;). IE: lab0002A51B9F16  HOSTNAME=lab`ifconfig eth0 |awk &#39;/HWaddr/ {print $5}&#39;|sed &#39;s/://g&#39;` 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I&#39;m sure there are more effecient commands that could be used here (I&#39;m no scripting geek), but this works. :) I spent a couple hours hunting for something like this and couldn&#39;t find it, so I hope it&#39;s of use to someone.&lt;/p&gt;
</content:encoded><category>linux</category></item>
<item><title>SoapBox Platform Possibilities</title><link>https://jdconley.com/blog/soapbox-platform-possibilities</link><guid isPermaLink="false">tag:blogger.com,1999:blog-1741199026308686058.post-7900123433520559771</guid><pubDate>Sat, 16 Sep 2006 16:38:00 GMT</pubDate><description>Our customers do some very interesting things with our platform, including: RPC – The asynchronous nature of XMPP along with its addressing and our platform make it ideal for…</description><content:encoded>&lt;p&gt;Our customers do some very interesting things with our platform, including:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;RPC – The asynchronous nature of XMPP along with its addressing and our platform make it ideal for application to application messaging. One of our customers wrote a .NET Remoting transport on SoapBox, and many use it for other custom RPC needs (some are below).&lt;/li&gt;
&lt;li&gt;Network gaming infrastructure – sending game data, hosting chat rooms, private chat during games, etc&lt;/li&gt;
&lt;li&gt;In class test taking – Tests are distribute to Tablet PC’s when students log in and results are tallied.&lt;/li&gt;
&lt;li&gt;Geographical Chat – Whiteboarding combined with maps and group conferencing.&lt;/li&gt;
&lt;li&gt;Financial Market Data – Real time data from the market flows into applications used by traders.&lt;/li&gt;
&lt;li&gt;Social Networking – Consumer social networking site using our platform for chat, content, and advertising delivery to the desktop.&lt;/li&gt;
&lt;li&gt;Emergency Alerting – “The nuclear power plant is melting down. Evacuate!”&lt;/li&gt;
&lt;li&gt;Remote Surveillance Control – Watch your surveillance cameras at home in any web browser and control them.&lt;/li&gt;
&lt;li&gt;Automated Manufacturing Alerting – “Line 5 is clogged. Attention required!”.&lt;/li&gt;
&lt;li&gt;Plain ole’ chat built into an existing application – Give users access to the people they need in the application they are familiar with.&lt;/li&gt;
&lt;li&gt;Build System Alerts – Our build system sends us messages as our daily builds runs, letting us know the status.&lt;/li&gt;
&lt;li&gt;Web Based Live Support – Communicate with customers live, through a web site.&lt;/li&gt;
&lt;li&gt;Voice and Chat on Ruggedized Handhelds - Push to talk through a contact list with presence, send messages, pictures, or go into walkie talkie mode.&lt;/li&gt;
&lt;li&gt;And the list goes on…&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Some have been in the news, some are still in &quot;stealth mode&quot;, but unfortunately I can&#39;t mention any names of companies. We will have some case studies coming out for a few of them.&lt;/p&gt;
&lt;p&gt;Some of these applications are built on our 2005 platform, but many are built on our upcoming 2007 release. We&#39;ve been working hard with our partners to make sure this upcoming release is something special. Here&#39;s a little overview of the new SoapBox platform.&lt;/p&gt;
&lt;p&gt;SoapBox Framework (now SoapBox Studio)&lt;/p&gt;
&lt;p&gt;The SoapBox Framework was our first product offering. We built and productized a framework knowing we’d want to build a server and an advanced communicator client. It started out as one framework, and has grown into quite a bit more. With the 2007 product release we will be distributing our frameworks in one package called the SoapBox Studio. They are all based on the same code base, which allows us to quickly add features to our entire product line. These frameworks include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Desktop Edition – Build desktop and web applications in .Net for Windows, Linux, and Solaris.&lt;/li&gt;
&lt;li&gt;Mobile Edition – Build mobile applications that run on PocketPC, Smart Phone, Windows Mobile, or Windows CE operating systems.&lt;/li&gt;
&lt;li&gt;Web Service Edition – This is my favorite. J A standard SOAP web service, built using our Desktop Edition on the back end, that allows you to integrate with any language that supports web services. This includes Java, ColdFusion, Flash, C++, Perl, Php, and more (basically every language out there).&lt;/li&gt;
&lt;li&gt;Server Administration Edition – All of the features that are available in our Management Console are available to you through public API’s. You can quickly perform tasks such as adding users, managing contact lists, and retrieving message archives.&lt;/li&gt;
&lt;li&gt;Server Edition –This allows you to build plug-ins to the SoapBox Server to manage users from your own custom user store, create custom components to service client requests, filter messages, do custom logging, and manipulate the way the server works in general.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;SoapBox Server&lt;/p&gt;
&lt;p&gt;The SoapBox Server is our flagship XMPP server product. It is based on our Desktop Edition Framework with additional layers to do everything a server needs to do. You can easily customize the Server to meet your specific needs through the SoapBox Framework Server and Administration SDK’s.&lt;/p&gt;
&lt;p&gt;SoapBox Communicator&lt;/p&gt;
&lt;p&gt;The SoapBox Communicator is our client software built on our SoapBox Framework Desktop Edition (as well as another layer that we will be productizing soon) and serves as an example of how to best utilize the framework for client side development.&lt;/p&gt;
&lt;p&gt;Other Key Platform Features&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Open, well normalized database – We use a strict Enterprise nTier model in the SoapBox Server. Our database is well normalized with stored procedures for all interactions. This makes it extremely easy to integrate users, contact lists, message archiving, and presence with any environment that can read or write to a database.&lt;/li&gt;
&lt;li&gt;Shared code base - Whether you’re writing an application for a Smartphone, or a server plug-in to handle workflow in a CRM application, your code interacting with SoapBox will look strikingly similar. This better utilizes your developer resources by focusing them on their business problem, not re-learning another API.&lt;/li&gt;
&lt;li&gt;Unprecedented vertical scalability - SoapBox Server will fully utilize any hardware you can throw at it.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We have been hard at work creating the best documentation and samples out there for any XMPP platform. Here are a couple of (draft) samples.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://www.coversant.net/downloads/Building%20Custom%20Packets.pdf&quot;&gt;Building Custom Packets&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.coversant.net/downloads/Building%20a%20Custom%20User%20Manager.pdf&quot;&gt;Building a Custom User Manager&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you would like advanced access to the SoapBox 2007 Platform, shoot us an email over at &lt;a href=&quot;mailto:support@coversant.net&quot;&gt;support@coversant.net&lt;/a&gt; and we&#39;ll get you on the beta list.&lt;/p&gt;
</content:encoded><category>soapbox</category><category>xmpp</category></item>
<item><title>Cross Platform Deployment Project Bootstrapper</title><link>https://jdconley.com/blog/cross-platform-deployment-project</link><guid isPermaLink="false">tag:blogger.com,1999:blog-1741199026308686058.post-8439273755609074001</guid><pubDate>Fri, 01 Sep 2006 17:13:00 GMT</pubDate><description>I think we are one of a very small set of companies out there building consumer grade, shrink wrapped products on .NET. Why? Well, I&#39;m not sure. It might have to do with…</description><content:encoded>&lt;p&gt;I think we are one of a very small set of companies out there building consumer grade, shrink wrapped products on .NET. Why? Well, I&#39;m not sure. It might have to do with Microsoft&#39;s positioning on the matter. All their documentation talks about enterprise deployments. It could also have to do with the runtime size. Some people think 50MB download for prerequisites is too much. In general, though, .NET, and Visual Studio 2005 especially, provide all kinds of great tools for building shrink-wrapped products. One of these is the Deployment Project.&lt;/p&gt;
&lt;p&gt;To create a working Deployment Project you simply set a few properties and point it at your main executable project. Whether it is a Windows Service, Winforms, or Web Project, you will get an installer that will run for most people. By default in Visual Studio 2005 the Deployment Project generates a bootstrapper Setup.exe. This will download and install MDAC 2.8 and the .NET 2.0 redistributable, if necessary. However, there is one caveat. It only works on x86 based operating systems! I have to admit, this caught me off guard. I expected to check a couple boxes in the UI and have everything just work on every platform where .NET would run. Unfortunately this is not the case.&lt;/p&gt;
&lt;p&gt;Luckily, the bootstrapper is &lt;a href=&quot;http://blogs.msdn.com/chrsmith/archive/2005/06/03/How_to_do_a_64bit_OS_check.aspx&quot;&gt;very customizable&lt;/a&gt;. Using a simple &lt;a href=&quot;http://msdn2.microsoft.com/en-us/library/ms164294.aspx&quot;&gt;MSBuild task&lt;/a&gt; and some XML files you can dynamically &lt;a href=&quot;http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnvs05/html/custom_pkg.asp&quot;&gt;build bootstrappers&lt;/a&gt; for any MSI or executable file. So, I put together some bootstrapper packages for .NET 2.0 on x86, x64, and IA64 platforms, MDAC on x86, Windows Installer 3.1 on x86, and SQL Express 1.0 SP1 on any platform. The result: I can click a few check boxes in a deployment project and not have to worry about changing my bootstrapper packages for each platform.&lt;/p&gt;
&lt;p&gt;Here is the bootstrapper set: &lt;a href=&quot;http://www.coversant.net/downloads/blogdownloads/jconley/CrossPlatformBootstrappers.zip&quot;&gt;CrossPlatformBootstrappers.zip&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The key to these bootstrappers working on all platforms is they do not fail if the platform doesn&#39;t match. They simply move on to the next bootstrapper. So you can choose all of our .NET 2.0 boostrappers in your Deployment Project, change the target platform of the deployment, and not have to remember to change your bootstrappers.&lt;/p&gt;
&lt;p&gt;In addition to the .NET 2.0 bootstrappers I also created a SQL Express 1.0 SP1 bootstrapper using SQLEXPR.exe, which will run on all platforms. However, instead of doing a default install of SQL Express, it installs a specific instance name. For us, this instance is SOAPBOX. You&#39;ll want to modify the bootstrapper package.xml and product.xml files to suit your needs for your SQL instance name (or just use the default). If the instance already exists on the computer, it won&#39;t be installed again.&lt;/p&gt;
&lt;p&gt;Earlier I mentioned MSBuild. A major key to creating shrink-wrapped products is being able to get builds out quickly and accurately. We use MSBuild for this. We have tons of custom tasks, but one of the MSBuild tasks that ships with the framework is called &lt;a href=&quot;http://msdn2.microsoft.com/en-us/library/ms164294.aspx&quot;&gt;GenerateBootstrapper&lt;/a&gt;. With this task you can point MSBuild at your Bootstrapper directory (the contents of the zip file), an msi, and a list of bootstrappers, and it will create a bootstrapper exe for you.&lt;/p&gt;
&lt;p&gt;Deployment Projects and I have a love/hate relationship. There are many things about them I don&#39;t like, but the bootstrapper piece is wonderful! So, in the upcoming 2007 builds of SoapBox products, expect to see a seamless installation including download on demand for all the prerequisites your system will need, on any platform.&lt;/p&gt;
</content:encoded><category>.net</category><category>install</category><category>soapbox</category></item>
<item><title>Using the MySql Command Line from C#/.NET</title><link>https://jdconley.com/blog/using-mysql-command-line-from-cnet</link><guid isPermaLink="false">tag:blogger.com,1999:blog-1741199026308686058.post-7735018220357202657</guid><pubDate>Wed, 02 Aug 2006 00:24:00 GMT</pubDate><description>We have added two new data access providers to the upcoming SoapBox Server 2007 release. We now support PostgreSql and MySql as well as Microsoft SQL and Oracle. The code for…</description><content:encoded>&lt;p&gt;We have added two new data access providers to the upcoming SoapBox Server 2007 release. We now support PostgreSql and MySql as well as Microsoft SQL and Oracle. The code for these databases has been in our server and test libraries for a couple of months and this last week it was time to add them into our post installation configuration wizard. We strive to make our setup process as simple as possible. You&#39;ll notice many improvements over the 2005 wizard. We have better auto-configuration and fewer wizard screens.&lt;/p&gt;
&lt;p&gt;One of our core philosphies here at Coversant is to make all of our software as easy to use as possible. Aside from testing, we spend more time doing this than any other R&amp;amp;D effort. Why is easy to use software so important? Well, the easier our software is to use the more you will like it and the less support we have to provide. We cut costs, you are happier. It&#39;s win/win. :)&lt;/p&gt;
&lt;p&gt;Adding the automated setup process for these new data access layers was supposed to be very straightforward. In our configuration utility it&#39;s all abstracted so I just implement a few classes, the DB guy gives me the scripts to run and I call the appropriate tool (mysql.exe, pgsql.exe, osql.exe, etc), which we ship with our server for your convenience. However, there is one big feature missing from the mysql command line tool. There is no way to specify a file to use as input! But, it does take standard input. So, typically, if i were running the tool from the command line I would do something like: &#39;mysql -uroot -p &amp;lt; &quot;c:\myscript.sql&quot;&#39;. If you&#39;re command line saavy you will know this redirects the file c:\myscript.sql as standard input into the mysql command line tool. I thought I could do this in .NET using command line arguments passed to the System.Process.ProcessStartInfo class. Well, I was wrong. It doesn&#39;t work (at least I couldn&#39;t figure out how to give it a file as stdin -- the &quot;&amp;lt;&quot; didn&#39;t work).&lt;/p&gt;
&lt;p&gt;So, what&#39;s the answer? Simple. Set the nifty RedirectStandardInput property and read the file into the Process.InputStream. Code follows:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;private void ExecuteSQLScript(string databaseName, string user, string password, string command, string filename, string server)        {            using (System.Diagnostics.Process p = new System.Diagnostics.Process())            {#if LINUX            p.StartInfo.WorkingDirectory = System.IO.Path.GetFullPath(this.InstallOptions.InstallDirectory);            p.StartInfo.FileName = &quot;mysql&quot;;#else                //grab the path from our installation options                p.StartInfo.WorkingDirectory = System.IO.Path.GetFullPath(System.IO.Path.Combine(this.InstallOptions.InstallDirectory, BaseScriptDirectory));                p.StartInfo.FileName = System.IO.Path.Combine(p.StartInfo.WorkingDirectory, &quot;mysql.exe&quot;);#endif                                //set all the startup options                p.StartInfo.CreateNoWindow = true;                p.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;                p.StartInfo.UseShellExecute = false;                p.StartInfo.RedirectStandardOutput = true;                p.StartInfo.RedirectStandardError = true;                //build the arguments for mysql                StringBuilder args = new StringBuilder();                if (!string.IsNullOrEmpty(password))                    args.AppendFormat(&quot;-p{0} &quot;, password);                if (!string.IsNullOrEmpty(server))                    args.AppendFormat(&quot;-h{0} &quot;, server);                if (!string.IsNullOrEmpty(databaseName))                    args.AppendFormat(&quot;-D{0} &quot;, databaseName);                if (!string.IsNullOrEmpty(user))                    args.AppendFormat(&quot;-u{0} &quot;, user);                if (!string.IsNullOrEmpty(command))                    args.AppendFormat(&quot;-e\&quot;{0}\&quot; &quot;, command);                else if (!string.IsNullOrEmpty(filename))                    p.StartInfo.RedirectStandardInput = true;                p.StartInfo.Arguments = args.ToString();                WTrace.TraceInfo(&quot;Run Script&quot;, this.GetType(), &quot;Executing: &#39;{0}&#39; with args &#39;{1}&#39; in working dir &#39;{2}&#39;&quot;, p.StartInfo.FileName, p.StartInfo.Arguments, p.StartInfo.WorkingDirectory);                //start up the process, and handle the redirected stdin and stdout -- send them to our trace lib                p.ErrorDataReceived += new System.Diagnostics.DataReceivedEventHandler(p_ErrorDataReceived);                p.OutputDataReceived += new System.Diagnostics.DataReceivedEventHandler(p_OutputDataReceived);                try                {                    p.Start();                    p.BeginErrorReadLine();                    p.BeginOutputReadLine();                    //read in the script file if one was specified and give it to stdin                    if (null != filename)                    {                        using (FileStream f = File.OpenRead(filename))                        {                            using (StreamReader reader = new StreamReader(f))                            {                                //we could do this one line at a time to be safe memory wise, but we know our scripts are small                                p.StandardInput.WriteLine(reader.ReadToEnd());                            }                        }                        //tell mysql we want to exit, otherwise the process will hang                        p.StandardInput.WriteLine(&quot;exit&quot;);                    }                    p.WaitForExit();                }                finally                {                    p.ErrorDataReceived -= new System.Diagnostics.DataReceivedEventHandler(p_ErrorDataReceived);                    p.OutputDataReceived -= new System.Diagnostics.DataReceivedEventHandler(p_OutputDataReceived);                }                if (p.ExitCode != 0)                    throw new MySqlException(&quot;SQL Command failed.&quot;, p.StartInfo.Arguments, &quot;&quot;, &quot;&quot;);            }        }        void p_ErrorDataReceived(object sender, System.Diagnostics.DataReceivedEventArgs e)        {            if (!string.IsNullOrEmpty(e.Data))                WTrace.TraceInfo(&quot;Run Script&quot;, this.GetType(), &quot;StdErr: {0}&quot;, e.Data);        }        void p_OutputDataReceived(object sender, System.Diagnostics.DataReceivedEventArgs e)        {            if (!string.IsNullOrEmpty(e.Data))                WTrace.TraceInfo(&quot;Run Script&quot;, this.GetType(), &quot;StdOut: {0}&quot;, e.Data);        }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Wow, that&#39;s a lot of code. Ok, so I probably didn&#39;t have to paste that much of it, but I wanted you to get an idea of the full extent of the method, and I think being able to run mysql scripts is useful.&lt;/p&gt;
&lt;p&gt;When all is said and done you now have two screens for installing to a MySql database: 1) enter username, password, and hostname 2) choose an existing or new database name. From there the installer figures everything else out automatically.&lt;/p&gt;
</content:encoded><category>.net</category><category>mono</category><category>soapbox</category></item>
<item><title>More on Interop</title><link>https://jdconley.com/blog/more-on-interop</link><guid isPermaLink="false">tag:blogger.com,1999:blog-1741199026308686058.post-1161897624541060473</guid><pubDate>Thu, 27 Jul 2006 04:00:00 GMT</pubDate><description>I&#39;m sitting on a plane on my way back to Sacramento (a whopping 1 hour flight) and I thought I&#39;d try to give a little more information about the interop event. After two days…</description><content:encoded>&lt;p&gt;I&#39;m sitting on a plane on my way back to Sacramento (a whopping 1 hour flight) and I thought I&#39;d try to give a little more information about the interop event. After two days of testing it appears as though we&#39;re actually very close to having quite a few fully interoperable XMPP implementations. As I mentioned last time, Monday was a cake walk. Unfortunately Tuesday wasn&#39;t quite so easy.&lt;/p&gt;
&lt;p&gt;Consensus was reached on Monday to start later on Tuesday. We wanted to do 10am, but had reservations at Jive&#39;s office to sample beers of the northwest at 5 (yeah they have some good beers) and play some XBox, so we decided to start at 9 instead. The morning session consisted mostly of protocol discussions that were very productive. We decided on the general protocol flow of PEP (Personal Eventing via Pubsub). This protocol addition allow us to create some very innovative and interesting extended presence features (more on this later) in future versions of SoapBox Communicator, and they&#39;ll be compatible with features in other clients such as Google Talk, GAIM, etc.&lt;/p&gt;
&lt;p&gt;I had some really good Thai food from a street vendor, and I&#39;m still not sick, so that&#39;s good. In fact it was some of the best Thai food I&#39;ve had in a long time, and I eat Thai about once a week.&lt;/p&gt;
&lt;p&gt;After lunch we got down to business with more interoperability testing. The goal: mutually authenticated TLS streams between servers per RFC 3920. A certificate authority was created, X.509 Certificates were generated, servers were configured, and then... it didn&#39;t work. Unlike the overwhelming success of Monday, Tuesday brought the skeletons out of the closet. We soon realized there were numerous breaking differences between OpenSSL, Java, and .NET based implementations of TLS. When we started, absolutely none of the servers were able to talk to each other over a fully trusted TLS connection. The interesting thing was we could all talk to another instance of our own servers. Hmmm.&lt;/p&gt;
&lt;p&gt;After a few hours of hacking and debugging we realized there was significant work that needed to be performed and we didn&#39;t have enough time to do it. We were able to get connected with a few of the servers, and vice versa, but there definitely wasn&#39;t a Happy Path for all. As a result the server to server TLS specifications in RFC3920 will be clarified, as we eventually reached consensus on what it all really means and how it should be implemented.&lt;/p&gt;
&lt;p&gt;In the very near future the &lt;a href=&quot;http://www.jabber.org/&quot;&gt;JSF&lt;/a&gt; will be facilitating ad-hoc interoperability testing over the internet. It will be managing domains (such as soapbox.xmpp.org, google.xmpp.org, etc) where all participating vendors and open source projects will host servers. These will be semi-private domains without open registration, but open to anyone developing XMPP applications that need to test interoperability.&lt;/p&gt;
&lt;p&gt;All in all, this was a very successful couple of days. We probably saved a good two months worth of bickering over e-mail lists to figure out protocol issues, verified that XMPP is in fact interoperable, and set the stage for future interoperability testing. We&#39;ll also be exploring fully automated tests, which Coversant will likely contribute to the JSF, to make sure everyone continues to play nice in the future. :)&lt;/p&gt;
</content:encoded><category>soapbox</category><category>xmpp</category></item>
<item><title>Interoperability - Yup, we got it covered</title><link>https://jdconley.com/blog/interoperability-yup-we-got-it-covered</link><guid isPermaLink="false">tag:blogger.com,1999:blog-1741199026308686058.post-3475430821530758052</guid><pubDate>Tue, 25 Jul 2006 06:54:00 GMT</pubDate><description>Today was the first day of the first ever official XMPP Interop Event. In fact, it was probably the first day of any open instant messaging and presence interop event, ever. We…</description><content:encoded>&lt;p&gt;Today was the first day of the first ever official &lt;a href=&quot;http://wiki.jabber.org/index.php/Interop_Event&quot;&gt;XMPP Interop Event&lt;/a&gt;. In fact, it was probably the first day of any open instant messaging and presence interop event, ever.&lt;/p&gt;
&lt;p&gt;We had showings from Coversant (yeah, that&#39;s us), Sun, SixApart (LiveJournal), Google, Jive Software, Jabber Inc, Sun Microsystems, and Process-one. Some of those names might sound familiar, and others not, but in the end what we ended up with was seven completely different XMPP server code bases/implementations both open and closed source, setup on a LAN and federating with each other. We spent more time configuring DNS, IP addresses, and other networking junk than we did fixing bugs that were hampering interoperability.&lt;/p&gt;
&lt;p&gt;As far as I know (who knows what everyone was hiding on their laptop screens) there were only a few major bugs that were found and they were on two of the very freshest of server implementations, one of which the vendor considers in &quot;pre-alpha&quot; release status. No, I won&#39;t tell you who, but I bet they release patches soon. :)&lt;/p&gt;
&lt;p&gt;So what the heck did we do all day? Well, we tested interoperability, obviously! But more specifically:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Inter-domain roster manipulation - Add and remove contacts on other servers.&lt;/li&gt;
&lt;li&gt;Inter-domain messaging - Can we actually hold conversations with each other?&lt;/li&gt;
&lt;li&gt;Inter-domain presence - Avatars, status messages, show states, etc&lt;/li&gt;
&lt;li&gt;pizza&lt;/li&gt;
&lt;li&gt;UTF8 support - Strange unicode characters in other languages in addresses, messages, and presence.&lt;/li&gt;
&lt;li&gt;Discussed quite a few of the enhancement protocols pending for the XMPP specification and came to concensus on some issues.&lt;/li&gt;
&lt;li&gt;Mingled with everyone and shared some anecdotes on implementing XMPP that pretty much only the people in that room would understand.&lt;/li&gt;
&lt;li&gt;beer&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;What does that mean to you, a loving Coversant customer -- you are a customer, right? Well, it means that you can securely talk through IM in a federated manner to your trading partners, friends, family, and arch enemies even if they aren&#39;t one of our customers. Yeah, we support that, and apparently it works. ;)&lt;/p&gt;
&lt;p&gt;#1 on the list for tomorrow, trusted TLS based inter-server connections. So we have the joy of setting up a trusted certificate authority and distributing certs. I bet setup will take longer than the interoperability testing itself, again.&lt;/p&gt;
</content:encoded><category>soapbox</category><category>xmpp</category></item>
<item><title>How to Build Scalable .NET Server Applications: Memory Management</title><link>https://jdconley.com/blog/how-to-build-scalable-net-server</link><guid isPermaLink="false">tag:blogger.com,1999:blog-1741199026308686058.post-7402889212575295063</guid><pubDate>Tue, 27 Jun 2006 04:24:00 GMT</pubDate><description>I&#39;ll get this out of the way from the start. This series of blogs will have nothing to do with ASP.NET or web services. However, if you plan on writing you own implementation…</description><content:encoded>&lt;p&gt;I&#39;ll get this out of the way from the start. This series of blogs will have nothing to do with ASP.NET or web services. However, if you plan on writing you own implementation of IIS in managed code this would probably be a good place to start. :) I also won&#39;t be providing very many code examples, as I&#39;d be flogged by our intellectual property lawyers. You will not be able to copy and paste and create your own scalable server. However, I hope to provide enough insight so you can avoid a big list of gotchas we have had to figure out the hard way. This is one piece of a huge puzzle, memory management. Yes, you do have to think about that in .NET, at least if you want to build a large scale application.&lt;/p&gt;
&lt;p&gt;For those who don&#39;t already know, SoapBox Server is a part of our SoapBox Collaboration Platform that supports the &lt;a href=&quot;http://www.xmpp.org/&quot;&gt;XMPP protocol&lt;/a&gt; as well most of the interesting &lt;a href=&quot;http://www.jabber.org/jeps&quot;&gt;JEP extensions&lt;/a&gt;. At the core of SoapBox Server is a highly efficient Socket server and thread machine capable of scaling into the hundreds of thousands of simultaneous users, and it&#39;s built 100% on .NET (C# now, but used to be VB).&lt;/p&gt;
&lt;p&gt;SoapBox Server is the first multithreaded Socket based server application I&#39;ve had the pleasure of working on. During the course of building the SoapBox Server into the extremely scalable and reliable system it is today I&#39;ve learned a few things (as has the rest of the team, I hope). Thanks to &lt;a href=&quot;http://www.coversant.com/blogs/cmullins&quot;&gt;Chris&lt;/a&gt; (who already had tons of experience with such things in Win32/C++), a few bloggers out there, some books, customers finding very interesting bugs, Windbg with Son of Strike, oh and Starbucks, I&#39;d say I&#39;m pretty well versed in the land of building scalable server applications. I&#39;m no &lt;a href=&quot;http://www.wintellect.com/TechnicalBioDetail.aspx?Tech=3&quot;&gt;Jeff Richter&lt;/a&gt;, mind you, but I feel I have now learned enough to at least speak intelligently about it.&lt;/p&gt;
&lt;p&gt;In that spirit I&#39;d like to share the fruits of our tuning and debugging work, which, if history repeats itself, will continue to evolve as we begin work on our next major revision of the product. First, I&#39;d like to repeat something I said a couple paragraphs ago, SoapBox now scales to hundreds of thousands of simultaneous connections with a single piece of server hardware. Think about that for a second. A user brings up an &lt;a href=&quot;http://soapbox.net/&quot;&gt;IM client&lt;/a&gt;, connects to SoapBox Server, and then holds that connection open until they Log Out. Repeat hundreds of thousands of times. This is no simple task. The .NET CLR does not provide a magic &quot;Process.Scalable = true&quot; property. We have invested hundreds of hours into tuning (maybe thousands) over the life of the server on classes of hardware varying from single processor laptops to 16-way Itanium2 systems with 64GB RAM. We&#39;ve been through four distinct processing models as well as quite a few iterative improvements on our Socket interaction layer. Basically we have ran the server under a bunch of different profilers under many scenarios, found slow bits of code, and fixed them. But I&#39;m not going to talk about profiling and performance tuning; perhaps another time. I&#39;m going to talk about memory and scalable applications.&lt;/p&gt;
&lt;p&gt;Every time your application creates a new Socket, Windows pulls memory from it&#39;s Nonpaged Kernel memory, which is simply physical memory that is reserved by the kernel and will never be paged out to disk. This block of memory has a finite limit and the kernel picks the limit based on the amount of phsyical RAM available to it. I don&#39;t know the exact algorithm, but with 4GB RAM it&#39;s usually somewhere around 150,000 TCP Socket connections, give or take. Want to see this in action? Simply create a loop that instantiates sockets. It will stop working eventually with a SocketException telling you there isn&#39;t enough buffer space. On top of this hard kernel level limitation, you also have to worry about how much memory each concurrent connection uses in your own application. In SoapBox we store a lot of information about each connection in memory in order to improve performance and decrease our IO operations. This includes things like the user&#39;s contact list, their last presence (available, away, busy, etc), authorization information, culture information, user directory information, etc. If we didn&#39;t hold this in memory we&#39;d have to hit a file, database, or some other out of process persistent store for the information every time we needed it. Being IO bound is no fun. Believe me, we started out that way.&lt;/p&gt;
&lt;p&gt;However, because of our extensive caching, SoapBox Server 2005 can only reliably handle about 20,000 simultaneous connections on the beefiest of 32 bit hardware (on 64 bit it&#39;s much, much, much higher -- I also have to admit we haven&#39;t stress tested the 2007 build on 32 bit hardware, it would probably be much higher now). It doesn&#39;t matter if you have 64GB RAM and 16 32bit processors, it we can still only handle 20,000 connections. Why, you ask? Well, it&#39;s because of the 2GB (well, really 3GB with a boot.ini switch) virtual memory limit per process in 32bit Windows. Without delving into managing your own memory your process is only allowed up to 3GB to play with. Typically, we use that up, or rather, .NET thinks we use it up, somewhere between 20,000 and 30,000 connections. Now why would I say &quot;.NET thinks we use it up?&quot; Story time!&lt;/p&gt;
&lt;p&gt;A little over a year ago one of our customers kept running into a very bad situation. As evidenced by the Event Log, SoapBox Server was crashing (insert shock and awe here). It was an irregular occurance, but it did happen. However, we did no take this lightly. This customer was running about 2,500 simultaneous connections on a Dual Xeon with Hyperthreading and 4GB ram and the /3GB switch set. It was plenty of hardware for the job, and probably overkill. However, the service was still crashing. We set them up with the Debugging Tools For Windows and had them startup the process to wait for a crash (another blog we&#39;ll have to write some day). After a few tries we got a dump with some useful information in it. The result? We were out of memory, sort of.&lt;/p&gt;
&lt;p&gt;In .NET when you call any socket operation and pass it a buffer, whether it be a send or receive, synchronous or asyncronous, it takes that buffer and pins it before giving it to the Winsock API&#39;s. Pinning, in a nutshell, is taking a .NET data structure and telling the .NET CLR memory manager not to move it, until it is explicitly un-pinned. The memory manager in the CLR is smart. As you allocate and deallocate memory it is constantly defragmenting it for you so the overall memory footprint is lower. There are quite a few really good/long/complicated articles on how this works so I won&#39;t bore you. However, pinning throws a wrench in this and the memory manager isn&#39;t quite smart enough to deal with it well (though it has gotten a lot better in 2.0). Basically, that buffer you want to put on the socket cannot move in memory (physically -- in terms of you virtual memory space) from the time the socket IO operation begins until it ends. If you look at the Winsock2 API&#39;s this is obvious, since the buffer is passed as a pointer. Anybody who&#39;s built this type of application in Winsock2 is probably saying &quot;DUH!&quot;. I&#39;d consider this a very leaky abstraction. Due to this behavior, it is quite easy to write a socket application in .NET that runs out of memory.&lt;/p&gt;
&lt;p&gt;Back to the story! Not only were we out of memory, but the there was only about 200MB worth of data structures in the heap. For those of you like me that use calc.exe for all your basic math let me figure that out for you, 200MB &amp;gt; 3GB. Uhh, say what? How the heck were we out of memory? Well, we ran into the shortfall of pinning and memory fragmentation. The cause of this was a small number of small pinned buffers, in our case 2KB each, that were high enough in the heap to cause fragmentation spanning over 2.8GB. Where did the other 2.8GB go, you ask? Well, is was there, allocated by our process, but not being used by our code. In Son Of Strike (SoS -- a command line plug-in to the Windbg debugging tool I hope you never have to use) this showed up as free, empty, unused space! It was just sitting there waiting to be used, but we still ran out of memory. I think I mentioned earlier the memory manager in .NET isn&#39;t so smart when it comes to fragmented memory and pinning, well, this is what happens in the worst case.&lt;/p&gt;
&lt;p&gt;Good thing for you, the answer to all your memory fragmentation and pinning woes is quite simple. Pre-allocate buffers for use by anything that will be causing pinning, and do it early on before there is a lot of memory thrash (when your application is rapidly allocating and deallocating a lot of memory). We created a simple class called a BufferPool that we use to pre-allocate a certain number of buffers. This pool can grow as need be, but it does so in large chunks and forces a garbage collection each time before the buffers are actually used. This considerably reduces the chances of fragmentation caused by pinned memory. If the pool starts off with 500 buffers, but then the 501st buffer is needed it will grow by a configurable value, typically another 500 buffers, and the induced garbage collection will cause these buffers to shift to the lowest possible point on the heap.&lt;/p&gt;
&lt;p&gt;Interestingly enough when we found this bug we already knew about the pinning behavior of socket operations, but had only solved half of it. All of our BeginReceive calls were using the BufferPool because we knew the buffers would remain pinned until we received data from a client, but the BeginSend calls were not using the pool. We had not even considered the fact that sending a few KB of data might take long enough to pin memory, fragment the heap, and cause an OutOfMemoryException. But there is one case where they do, timeouts. The Windows TCP subsystem is very forgiving. If a client loses its connection and the server isn&#39;t explicitly told about it, the next piece of data you try to send to that client socket will end up being pinned while the TCP subsystem waits for the client to respond. It can take up to 5 minutes with the default configuration of Windows for the TCP subsystem to figure out the client isn&#39;t really there. During that entire time your buffer is pinned in memory. *poof* OutOfMemoryException.&lt;/p&gt;
&lt;p&gt;Unfortunately, pre-allocating buffers does not completely fix the issue of running out of memory. There are also some other limits to the size of a .NET process&#39;s virtual memory space that are very complicated and I won&#39;t talk about, but basically you end up with anywhere from 1/2 to 2/3 usable virtual memory without running the risk of OutOfMemoryException. So, if you have 2GB virtual memory available (standard on a 32bit machine), you end up with about 1.3GB you can actually use reliably. Of course, this varies, and some applications will be able to use more, or maybe less. Your mileage may vary.&lt;/p&gt;
&lt;p&gt;Don&#39;t fret, all of the issues I&#39;ve talked about in here have been fixed since SoapBox Server 2005 SR1. And with the most common usage patterns people were not actually affected to begin with.&lt;/p&gt;
&lt;p&gt;I hope this was at least marginally interesting to someone. :) Next up, I&#39;ll probably talk about limitations we discovered in the Windows Socket infrastructure, or maybe async IO, IOCP, and worker threadpools, or maybe how in the world we actually test at this scale. Only time will tell, unless Chris beats me to it.&lt;/p&gt;
</content:encoded><category>.net</category><category>async</category><category>soapbox</category><category>tuning</category></item>
<item><title>Fun Installing Vista Beta 2 on AMD x64</title><link>https://jdconley.com/blog/fun-installing-vista-beta-2-on-amd-x64</link><guid isPermaLink="false">tag:blogger.com,1999:blog-1741199026308686058.post-5719775486610590806</guid><pubDate>Fri, 02 Jun 2006 19:50:00 GMT</pubDate><description>As a self proclaimed geek and MSDN subscriber I feel as though it&#39;s my duty to explore all the new software that Microsoft comes out with. This last week I have been embarking…</description><content:encoded>&lt;p&gt;As a self proclaimed geek and MSDN subscriber I feel as though it&#39;s my duty to explore all the new software that Microsoft comes out with. This last week I have been embarking on one such journey. Working with beta software is always a bit trying, but tack on a beta driver model and a &quot;new&quot; hardware platform (x64) and things get really interesting.&lt;/p&gt;
&lt;p&gt;Vista Beta 2 was released to MSDN about a week ago. The next day I fired up my DVD burner and started messing around. About four hours later I had a working installation. Why so long? Well, because my workstation is an AMD NForce 4 x64 system and boots from the onboard SATA RAID. Apparently this is not one of Microsoft&#39;s test platforms. I had an experience similar to &lt;a href=&quot;http://www.nforcershq.com/forum/finally-got-nforce-raid-to-work-with-vista-vt65055.html&quot;&gt;this guy&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I had to run the Vista install from an existing Windows installation. It simply would not work when I attempted to boot from the dvd. I never got an option to load drivers. Nvidia recently released beta &lt;a href=&quot;http://www.nzone.com/object/nzone_downloads_nforce_vista_x64_beta2.html&quot;&gt;Forceware drivers&lt;/a&gt; for Vista x64. I assumed these would have the RAID drivers I needed to install Vista, afterall they did have the appropirate txtsetup.oem file and seemed to be correct. After a few attempted installations, blue screens, automatic reboots, and hangs, I decided that my assumption was bad. Lesson learned: to install Vista x64 on an Nforce 4 RAID use the XP x64 Nforce4 RAID and SATA drivers. Yup, that&#39;s right. Well, almost.&lt;/p&gt;
&lt;p&gt;If you&#39;re like me and want to use the latest Nvidia XP x64 drivers you&#39;ll be greeted with a black screen telling you that your drivers are corrupt after the first setup reboot. Say wha? Lucky for you, they aren&#39;t. This is a &lt;a href=&quot;http://blog.eweek.com/blogs/eweek_labs/archive/2006/01/23/4899.aspx&quot;&gt;feature&lt;/a&gt; of Vista x64. Hit F8 at the boot screen and choose to disable driver signature verification. Of course, hitting F8 EVERY time you boot your computer is not going to be very fun. Luckily (for now) there is an application called bcdedit (just run &quot;Bcdedit.exe –set nointegritychecks ON&quot;) that you can use to disable signature verification after you get into your desktop. Oh, don&#39;t forget to right click on the Command Prompt link in your start menu and choose &quot;Run as Administrator&quot; before trying to run this command, or it will tell you &quot;Access is Denied&quot;. Yay security! I should definitely mention that &lt;em&gt;Vista prompted me to allow this action&lt;/em&gt; (VPMTATA), at least once.&lt;/p&gt;
&lt;p&gt;Oh yeah, I almost forgot, after you finally get to your desktop Vista will keep telling you that it has found an unknown device. This is your RAID controller; the one with XP drivers. Point the device wizard thingy to the inf file (VPMTATA) of the Forceware Vista x64 Beta drivers and this annoyance will go away. You&#39;ll also need to install drivers (VPMTATA) for the Nforce4 audio chipset.&lt;/p&gt;
&lt;p&gt;On the plus side, Vista had drivers for my Geforce 7800GT and Nforce4 gigabit network card. It even figured out I had dual monitors (VPMTATA), picked the max resolution for both (VPMTATA), and presented a neat little dialog that let me choose the desktop layout (VPMTATA). Of course, I wanted to upgrade to the latest ones from Nvidia. This is usually straightforward.&lt;/p&gt;
&lt;p&gt;I ran the setup exe (VPMTATA) for the Nvidia Vista Beta 2 Geforce drivers. It extracted stuff (VPMTATA), ran the second installer exe (VPMTATA), and then failed with some cryptic error messages I probably should have written down and submitted as bug reports. Subsequent attempts to run the installation package (VPMTATA) resulted in an error about running 32 bit uninstaller code on a 64 bit platform. I was very confused, didn&#39;t want to spend much time on it, and gave up.&lt;/p&gt;
&lt;p&gt;A few days later I had an epiphany - &quot;I should just try to update the Microsoft Geforce driver with the inf&quot;. Duh. Well, I opened up the Device Manager (VPMTATA) and clicked update drivers (VPMTATA). Viola! The drivers were upgraded. Though, I have no idea if there are any control panels with these drivers (as there are in XP) since I couldn&#39;t run the full setup. Ah well, at least I have better video acceleration.&lt;/p&gt;
&lt;p&gt;I&#39;ll be back later for my accounts of fun with Vista. After a week of use, I think I could write a book. However, it definitely hasn&#39;t all been bad (though VPMTATA) and I will continue to use Vista as my primary OS until it does something very mean or simply won&#39;t allow me to get things done.&lt;/p&gt;
</content:encoded><category>windows</category></item>
<item><title>.net 2.0 web service hair puller</title><link>https://jdconley.com/blog/net-20-web-service-hair-puller</link><guid isPermaLink="false">tag:blogger.com,1999:blog-1741199026308686058.post-2083274888998170874</guid><pubDate>Fri, 12 May 2006 22:02:00 GMT</pubDate><description>Every couple of weeks I spend four hours doing something that should take five minutes. It just happened, and now I feel compelled to take another few minutes and explain so it…</description><content:encoded>&lt;p&gt;Every couple of weeks I spend four hours doing something that should take five minutes. It just happened, and now I feel compelled to take another few minutes and explain so it doesn&#39;t happen to you. Not only did I waste my time, but the time of another one of our developers. What might waste four hours, you say?&lt;/p&gt;
&lt;p&gt;We recently migrated our entire web site to .NET 2.0 and a new portal. Since we were building a new web site anyway we thought, &quot;What the heck, let&#39;s re-factor the licensing subsystem. The database was hacked together over three years and we don&#39;t want no stinkin&#39; .NET 1.1 code running on our shiny new site!&quot; Well, this didn&#39;t turn out exactly as planned.&lt;/p&gt;
&lt;p&gt;The SoapBox licensing web service is quite simple. There&#39;s a single method called &quot;Activate&quot; that takes in a unique hash of some information on the user&#39;s computer (so we can track duplicate usages) and the serial number. It returns an XML document containing all the license information, signed with our private key, that the SoapBox Server then validates with the embedded public key. That&#39;s it.&lt;/p&gt;
&lt;p&gt;We get a call from a customer today saying they can&#39;t enter a license key into the MMC. They&#39;re getting a wonderfully descriptive &quot;Object reference not set to an instance of an object&quot; error. We immediately kick into debug mode. Afterall, if a potential customer can&#39;t enter in our trial key they&#39;re going to get upset and likely just give up on using it all together.&lt;/p&gt;
&lt;p&gt;After a little debugging we found the web service wasn&#39;t returning the license xml document like it should have been. This was _very_ weird, considering our &lt;a href=&quot;http://www.coversant.com/licenses&quot;&gt;licensing page&lt;/a&gt; uses the same web service as our MMC and it was working just fine with the exact same parameters. Much head to wall interaction took place and we had another breakthrough, the web method wasn&#39;t receiving any data from the parameters. The serial number was null!&lt;/p&gt;
&lt;p&gt;Now we bust out the packet sniffer. After careful examination, a new mini test application to call the service, and three Diet Cokes, we found the problem.&lt;/p&gt;
&lt;p&gt;Apparently, during the migration and re-factoring process, we missed a character in a copy/paste operation. That&#39;s right, the trailing &quot;/&quot; on the namespace declaration for the web service.&lt;/p&gt;
&lt;p&gt;This in itself is not such a suprise. However, the suprise is that .NET did not throw a &quot;There is no matching web method you dummy&quot; exception. No, it didn&#39;t throw an exception at all. Instead it called the correct web method, but did not pass in any of the parameters. Oiy.&lt;/p&gt;
&lt;p&gt;It turns out our &lt;a href=&quot;http://www.coversant.com/licenses&quot;&gt;licensing page&lt;/a&gt; was working because the web reference was created after the new licensing service was put in place. It all makes sense now... Time for a beer.&lt;/p&gt;
</content:encoded><category>.net</category><category>asp.net</category></item>
<item><title>from the trenches of my first software startup</title><link>https://jdconley.com/blog/from-trenches-of-my-first-software</link><guid isPermaLink="false">tag:blogger.com,1999:blog-1741199026308686058.post-5102928330552291797</guid><pubDate>Tue, 09 May 2006 21:53:00 GMT</pubDate><description>I was born and raised an entrepreneur (I&#39;m pretty sure that&#39;s how you speel that). During my lifetime my dad never had a single &quot;real job&quot;. He has always been a small business…</description><content:encoded>&lt;p&gt;I was born and raised an entrepreneur (I&#39;m pretty sure that&#39;s how you speel that). During my lifetime my dad never had a single &quot;real job&quot;. He has always been a small business owner. From a carpet cleaning business, to a trucking company, to a coffee shop, he was always working on something he could call his own. Every time we get together we end up talking about businesses we&#39;d like to start. If only I had the time. . . Somehow, after seeing him (and my mom) constantly working at least 80 hour weeks, stressed out, and exhausted, I still decided I wanted to start a company.&lt;/p&gt;
&lt;p&gt;At the end of high school, and for a while after, I had a computer repair business with a really cute name and no business plan whatsoever. This lasted about six months. It turns out to be real work, and it&#39;s quite difficult to find people that are good enough to do that sort of work for very little pay. I&#39;m really very interested in how &lt;a href=&quot;http://www.geeksquad.com/&quot;&gt;Best Buy&lt;/a&gt; pulls that one off, though I assume they just have a good process and the people don&#39;t need to be all that great (no offense geeks -- I owe you guys many hours of my time that has been saved because I didn&#39;t have to help out my mother in law with her digital camera).&lt;/p&gt;
&lt;p&gt;Ok, back on topic, sort of. A few years prior to my repair business I had fallen in love with computer programming. I wrote little programs to do all sorts of interesting things. Of course, I didn&#39;t work on anything that took more than a few weeks of my time and only built things that were interesting to me. Ah, the good old days! I went into the professional world when I turned 18 and started writing code for a living. Wow, what a change. Who knew coding could be so much fun?! &quot;Wow, I get to program against another database and improve business processes! Woohoo!&quot;&lt;/p&gt;
&lt;p&gt;Needless to say, the life of a professional internal software developer was not in my cards. Even though I was making way too much money for my age as a &quot;consultant&quot; (that&#39;s what the recruiters like to call you, even though you&#39;re really just staff augmentation and under a different category on someone&#39;s budget), at about age 20 I started getting very restless. Luckily I met some like minded individuals (Jason and Chris) and Winfessor (Coversant&#39;s old company name) was born.&lt;/p&gt;
&lt;p&gt;For the last few years, in between consulting engagements (we&#39;re boot strapped), we&#39;ve been building the SoapBox products. Of course, we haven&#39;t only been building software, we&#39;ve been building a business. Lucky for me, my role is still primarily building the technology. It continues to be a wonderful, trying, stressful, exciting, sleepless, humbling experience.&lt;/p&gt;
&lt;p&gt;Here are some tidbits, in no particular order, that I&#39;ve picked up along the way, from learning both the easy way and the hard way. It&#39;s free (and probably bad) advice from my limited experience aimed at any programmers out there that want to start a company around a software product. I&#39;ll probably write some more specifics at some point.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Have at least one flagship customer to start with, mainly for promotional purposes, but ideally one that will help fund the project.&lt;/li&gt;
&lt;li&gt;Work full time on it. Hire others to do your consulting or other revenue generating work so you can focus, or get funding.&lt;/li&gt;
&lt;li&gt;Don&#39;t work so hard. There is always more work to do, even if you work 140 hours/week.&lt;/li&gt;
&lt;li&gt;Start small (ideally around 6mo development) and iterate from there.&lt;/li&gt;
&lt;li&gt;Build it like you would an enterprise project - component based, easily maintainable and easily expandable.&lt;/li&gt;
&lt;li&gt;Hire people to do things you aren&#39;t good at or learn to do them. Web site, graphics, brochures, accounting, sales, etc. Writing code is an itty bitty teeny weeny piece of your business.&lt;/li&gt;
&lt;li&gt;Figure out how to start getting revenues, quickly, and set reasonable goals.&lt;/li&gt;
&lt;li&gt;Don&#39;t look too far out into the future. Have a plan, but don&#39;t be scared to change it.&lt;/li&gt;
&lt;li&gt;Any software you build needs to be extremely easy to use and install. This alone will win many sales in a head to head battle with your competitors (yes, you will have competitors).&lt;/li&gt;
&lt;li&gt;FOCUS! Do one small thing better than anyone else, and then move on to the next.&lt;/li&gt;
&lt;li&gt;Don&#39;t pretend to be a big company. You have a lot of advantages being the small guy and people willing to work with small companies know it.&lt;/li&gt;
&lt;li&gt;Do something unique that your market needs.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That&#39;s all I&#39;ve got for now. We&#39;re constantly growing and learning. I imagine my advice will evolve as the Coversant experience continues. In the end, the freedom, excitement, and financial possibilities of a startup outweigh the pains, at least for me. I also just realized I use way too many parenthesis when I write (maybe I&#39;ll work on that).&lt;/p&gt;
</content:encoded><category>business</category></item>
<item><title>FakeOutTheUserToThinkWeDontUseAnyMemory</title><link>https://jdconley.com/blog/fakeouttheusertothinkwedontuseanymemory</link><guid isPermaLink="false">tag:blogger.com,1999:blog-1741199026308686058.post-6390406425317569855</guid><pubDate>Mon, 08 May 2006 22:28:00 GMT</pubDate><description>There comes a time in every project where the developers realize we are building software for the users, rather than for ourselves. A user&#39;s perception can be the difference…</description><content:encoded>&lt;p&gt;There comes a time in every project where the developers realize we are building software for the users, rather than for ourselves. A user&#39;s perception can be the difference between a good and a bad reference, and we all know how detrimental bad word of mouth can be. This unfortunate reality hit me square in the face recently when I was told by a customer that &quot;your application is bloatware&quot;.&lt;/p&gt;
&lt;p&gt;Any desktop application with a user interface, written in .NET, that does anything interesting, can easily be mistaken for bloatware. It&#39;s quite easy to create a super elegant application with no memory leaks that appears to use 50MB or more of memory. I say appears, because the figure everyone sees in Task Manager is the &quot;Working Set&quot; size. Users (myself included, up until recently) see large working set sizes as a sign of bloatware and poor programming.&lt;/p&gt;
&lt;p&gt;This is simply not the case. The working set is more along the lines of the amount of physical memory the OS thinks your application might need or needed at one point, including shared memory and all sorts of other complicated things that .NET developers aren&#39;t supposed to have to think about. If your system was in need of physical memory for other processes much of this perceived bloat would either be reclaimed and put to better use, or paged out to disk.&lt;/p&gt;
&lt;p&gt;At the end of the day, the reality of the situation doesn&#39;t matter. Your users think your application is bloated. What do you do? Well, you FakeOutTheUserToThinkWeDontUseAnyMemory.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;using System.Diagnostics;namespace Coversant.Utility {  public static class MemoryUtility  {      private static volatile bool _enabled = true;      public static void FakeOutTheUserToThinkWeDontUseAnyMemory()      {          if (!_enabled)              return;          try          {              Process curProc = Process.GetCurrentProcess();              curProc.MaxWorkingSet = curProc.MaxWorkingSet;          }          catch          {              //Some users won&#39;t have permission to adjust their working set.              _enabled = false;          }      }  }}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Yep, that&#39;s it. Call that method (.NET 2.0 only -- &lt;a href=&quot;http://www.ddj.com/dept/windows/184416804&quot;&gt;in 1.x you had to P/Invoke&lt;/a&gt;) and watch the magic happen. In our applications we set it up on a timer that runs every 30 seconds and after any events we know will raise the working set, usually after loading new assemblies or after a window is closed . Running this code causes Windows to free up as much of the working set as possible. Usually this sends most of your bloat to the page file where it will remain forever. In our case, the application had a 50MB working set and really only needed about 10MB of physical memory after it was running. There is, however, one big gotcha. An application can only attempt to adjust its working set if it is running with appropriate permissions (typically a local Administrator).&lt;/p&gt;
&lt;p&gt;Yes, your users perceptions are reality. Using this trick/hack helps keep reality in line.&lt;/p&gt;
</content:encoded><category>.net</category><category>tuning</category><category>winforms</category></item></channel></rss>
