Monday, November 16, 2009

Using Command-line arguments in Windows Services – a “gotcha”

This can’t really be considered a “gotcha” more than just a “pay careful attention to the perhaps unintuitive documentation” scenario.  Also, this assumes basic knowledge of creating Windows Services.

So here’s the situation: I wrote a Windows Service, and I wanted to optionally enable verbose debug output (since services are a bit of a pain to debug) using a command-line option.  Services, after all, can be started with command-line arguments.  But regardless of what I entered as the command-line arguments, the OnStart(string[] args) method of my service would always report that “args” was empty – that is, no arguments.

After some quick Bingoogling, here’s what I found:

The arguments in the args parameter array can be set manually in the properties window for the service in the Services console. The arguments entered in the console are not saved; they are passed to the service on a one-time basis when the service is started from the control panel.

I still thought that I was doing the right thing, by going to my service’s properties, typing command-line arguments, clicking OK and then right clicking the service and choosing Start:

image

image

But no luck!  The solution was very simple: Click Start from within the Properties window.  As soon as you click OK (which intuitively would seem to save the changes to the Start parameters, as is the case in every other properties dialog in the history of mankind), the Start parameters disappear.

Saturday, October 31, 2009

Pressure Sensitivity Problem with Wacom Bamboo Pen Tablet in Windows 7

Okay, this isn’t my usual coding-related post, but I hope it helps someone.  There are a million different threads about Wacom tablets not working properly with various software on various system configurations, and there’s no shortage of suggested solutions, so I’ll describe my specific situation and its specific solution:

Problem: Wacom tablet pen pressure sensitivity does not work in Adobe Photoshop CS4.  More specifically, it draws at full brush thickness all the time, unless I double-tap the tablet quickly and then begin drawing immediately after, which surprisingly allows pressure sensitivity to work.

My Configuration: Windows 7 Ultimate, Wacom Bamboo Pen tablet (the most basic model), Adobe Photoshop CS4 (as mentioned above)

Solution: In short, disable using the “press and hold” pen action as a right-click equivalent in the Windows tablet pen control panel.  To do this:

Click the Windows button, and in the search box type “Change tablet pen settings".  Open the item that appears.

image

In that dialog, in the Pen Options tab (the default), in the Pen actions group, select the Press and hold pen action and then click the Settings… button.

image

Then, in the dialog that appears, uncheck Enable press and hold for right-clicking and click OK.

image

Windows’ Tablet PC settings are fighting with the tablet’s usefulness, doing their best to turn it into a primary input device rather than a dedicated drawing instrument.  In my specific case, you’ll notice that every time you tap the pen and start drawing (interpreted by Windows as a “tap and hold”), a circle will start drawing around the tap location, and once it finishes drawing, the equivalent of a right-click is received.  This is not a Wacom thing; it’s a Windows thing, and it’s messing with your ability to use your pen with proper pressure sensitivity.

Since my Bamboo tablet pen has a button on it which maps to a right-click by default, I don’t need the “press-and-hold” right-click functionality, and you likely don’t either.

I hope this saves someone some frustration.

Wednesday, October 28, 2009

GetHashCode is useful, who knew?

If you’re like me, you’re inclined to lazily ignore warnings to override object.GetHashCode for your custom types if you’ve already overriden object.Equals.  If I’m using a Dictionary and using one of my objects as a key, then sure, I can see the point.  But if I’m just throwing it in a generic List, object.Equals is good enough, right?

Well, yes, but apparently this isn’t a safe assumption to make for any given collection type or operation.  I learned this the hard way with LINQ’s Enumerable.Intersect method (an extension method of IEnumerable<T>).

Without going into detail about set theory, the Enumerable.Intersect method will take two collections of objects, and return a collection of objects which both source sets contain.  So, for example, if I have two sets of ints:

A = { 1, 5, 7, 9 }
B = { 4, 5, 9, 13 }

The intersected set would contain only the values that both sets share:

{ 5, 9 }

Now, if the items in my sets are of my own custom type, I thought it would be sufficient to override object.Equals for this type.  But no, if I do this, Enumerable.Intersect will return an empty collection, indicating that none of the objects are equal, even if they areWhen I implemented object.GetHashCode as the compiler repeatedly pestered me to do, everything worked fine.

Friday, August 28, 2009

ServerTooBusyException in WCF, possible cause

I wanted to post this confusing error and solution in case this can help anyone else.  Here is my general situation:

1. I was testing my WCF service hosted on a remote IIS server.  I had an identical IIS setup on my local development machine, and I wanted to switch to use it instead for better debugging support. 

2. When I ran the exact same service-calling code on my local machine, service calls always hit the ServerTooBusyException exception.  I checked my local IIS setup, confused that I was getting a different result when all of the virtual directories, ports, bindings, etc. were identical to the remote server.  I manually accessed my service’s URL in a local web browser, i.e. http://localhost/MyService/MyService.svc.  I got the error:

Service Unavailable


HTTP Error 503. The service is unavailable.

Huh?  Not very descriptive.  And being a newbie, I have had no luck following the convoluted steps of getting any sort of service trace logging to work – and I wasn’t even sure if this would help.  (As an aside, PLEASE comment if you know how to enable the type of logging that ultimately would have revealed this problem.)

3. Finally I found a vague comment on a forum regarding changed credentials, and it dawned on me: The account associated with the app pool I was using had had its password changed recently, and I hadn’t updated it on my local server to reflect this.  Once I re-set the credentials for the app pool user, everything worked perfectly.

 

I hope this post saves a headache or two.

Friday, August 7, 2009

Code Analysis / Team Foundation context menu items missing!

I had an issue recently in which my Team Foundation (2008) enlistment appeared to be partially corrupt.  Some of the symptoms:

1. My “Work Items” folder had a red ‘x’ next to it permanently; I could never connect to my work items on my main PC (but I could from other PCs).

2. When right-clicking on a Code Analysis warning in the Error List panel of Visual Studio, I didn’t get the usual options of “Create Work Item” and “Suppress Message(s)”.

3. Some of the Team menu items were missing, or their sub menu items were greyed out, and displayed error messages such as “value does not fall within the expected range.”

I tried all sorts of painful, time-consuming solutions, even uninstalling/reinstalling everything, but ultimately the solution was simply to delete my local app data Team Foundation Cache folder, located here:

%localappdata%\Microsoft\Team Foundation\2.0\Cache

I hope that someone finds this and it saves them hours of headache.

Monday, July 27, 2009

Resolving “CREATE DATABASE permission denied in database 'master'. (Microsoft SQL Server, Error: 262)”

To those of you who have Microsoft SQL Server Management Studio, and you’re un-hardcore users like myself who simply want to create a simple database to play around with, you might run into this cryptic error when you try to create a new database. 

image

Naturally the help URL link provided merely consoles you with an all-too-common “sorry, we can’t help” message.

We're sorry

There is no additional information about this issue in the Error and Event Log Messages or Knowledge Base databases at this time. You can use the links in the Support area to determine whether any additional information might be available elsewhere.

Given that you’re not a hardcore MS SQL Server user, and neither am I, this error makes little sense.  There’s a system database called master, but I’m not creating that… I’m creating my own database, called ‘MyDatabase’.  I don’t care about the permissions to the database called ‘master.’  Further, I’m the admin on my PC, and I’m using “Windows Authentication”… to me that sounds like I should have the highest possible access to do whatever the heck I want with my local SQL server. 

Well, yeah, you do, but here’s the catch: You have to run the damn SQL Management Studio as administrator.  That’ll make this hellish error go away.  I sincerely hope that this blog post has saved at least one person from the frustration they might otherwise endure.

Sunday, May 3, 2009

Oh noes! Expectation Failed (417) in my WCF service at Tully’s

Just when I thought my WCF service was working properly with regard to different network set-ups (i.e. my work network versus my home network), I found an annoying error occurring whenever I try to call one of my service methods.

Aside: Is that the proper terminology? Do I say: “Whenever I call a service method” or instead do I say: “Whenever I connect to my service” or : “Whenever I access my service” ? I’m not sure of the proper lingo.

image

For the benefit of search engines, that’s: “ProcolException was unhandled. The remote server returned an unexpected response: (417) Expectation failed.”

I verified (via remote desktop) that my home PC is still getting a proper response from the service. So what’s going on? Why am I unable to live up to my web service’s expectations when I’m on my laptop at Tully’s? Well, either it has something to do with my local system configuration, or it has something to do with the network settings here. I don’t really have a convenient way to test another network here, so I’m going to work on the hypothesis that it has something to do with Tully’s wifi network configuration. This seems especially likely given that my web browser is having a heck of a time loading web pages fully. Nevertheless, I don’t want to lazily write this off as an extreme case. I’ll need to use Google to get to the bottom of this.

So, after looking at Google, I’ve found several forums in which people have had a similar problem, and a solution which seems to work is described on my new favorite code-help site, stackoverflow.com:

System.Net.HttpWebRequest adds the header 'HTTP header "Expect: 100-Continue"' to every request unless you explicitly ask it not to by setting this static property to false:

System.Net.ServicePointManager.Expect100Continue = false;
Some servers choke on that header and send back the 417 error you're seeing.

Sure enough, I added this line before my call to the WCF service and everything worked as expected. Of course, it’s still basically magic to me. I understand little about how these requests and responses behave. MSDN demystifies it a little bit more:

When this property is set to true, client requests that use the POST method expect to receive a 100-Continue response from the server to indicate that the client should send the data to be posted. This mechanism allows clients to avoid sending large amounts of data over the network when the server, based on the request headers, intends to reject the request.

For example, assume the Expect100Continue property is false. When the request is sent to the server, it includes the data. If, after reading the request headers, the server requires authentication and must send a 401 response, the client must resend the data with proper authentication headers.

If this property is true, the request headers are sent to the server. If the server has not rejected the request, it sends a 100-Continue response signaling that the data can be transmitted. If, as in the preceding example, the server requires authentication, it sends the 401 response and the client has not unnecessarily transmitted the data.

Changing the value of this property does not affect existing ServicePoint objects. Only new ServicePoint objects created after the change are affected.

The Expect 100-Continue behavior is fully described in IETF RFC 2616 Section 10.1.1.

Sunday, April 19, 2009

My Experience Trying to Host a WCF Service on a Shared Hosting Plan

So I was about to try to host a WCF service on my shared hosting plan, and I was excited given my knowledge that such a tutorial had already been written – or so I thought.  I began by reading through some of the many WCF service creation tutorials available on the web.  These explained the fundamentals, and gave the steps required to create a working WCF service.  I was able to host these locally without much trouble, given that Visual Studio 2008 automagically does everything for you.  I can shut off my brain (a bad habit in coding, mind you) and trust that everything will work for me behind the scenes.

But once I was ready to test in a shared hosting environment, I drew a blank.  What the heck was I supposed to do?  No sweat, I told myself.  I just referred to an article written by our very own D-roc entitled: “Hosting WCF Services on a Shared Hosting Plan.”  Much to my horror, this article didn’t explain the first thing about hosting a WCF service on a shared hosting plan; it merely warned me of a single “gotcha” that could occur.  It should have been titled: “One Thing To Look Out For When Hosting a WCF Service on a Shared Hosting Plan.”  It lost me on the fourth sentence:

If you would try to run a web service using this markup,

<%@ ServiceHost Language="C#" Debug="true" Service="SomeService" %>

Huh?  What’s this markup?  Where does that markup live?  I don’t have that markup anywhere in my code.  Is that supposed to be on my web server somewhere?  Where do I find/put it?

I had to refer back to one of my tutorials at codeidol.com, under the topic of WCF Essentials –> Hosting.  I was a little worried because these articles seem a little outdated, but not too outdated, I hoped.  In this topic, the author describes how to use IIS (Microsoft Internet Information Server) hosting.  Now, I don’t know much about IIS, but I know that it’s Microsoft’s server software for allowing servers on the internet to host web pages, FTP sites and that sort of thing.  I also know that my web hosting company has IIS installed and lets me administer it somehow.  So I figured this was my best bet.

Specifically, the article said that in order to host a service, I need to create a “virtual directory” and “supply an .svc file”.  Okay, I’d heard the term “virtual directory” before but I had no idea how to create one.  I was guessing it’d be a setting in my web host administration tool, so I looked.  Sure enough, in my web host administration control panel, I had a menu heading called “IIS Manager” and a setting called “Set Virtual Dir.”  I also noticed way too many settings that had to do with FrontPage extensions.  Microsoft doesn’t even make FrontPage, and hasn’t since 2003.  Why is this a big supported feature?  But I digress:

image

So I clicked this option and it brought up a page that let me specify the name of the virtual directory, and the actual directory where it should point.  I created a directory and made the virtual directory the same name.  Hopefully your web host will have something similar:

image

Now, I needed to somehow let the web server know that I have a service there.  Well, I don’t yet, but I wanted to make it think that I did.  So I opened up notepad and created an .svc file.  Now, rather than using the sample from codeidol.com, I decided to use D-roc’s example, since I assumed that his would be the “newer” of the two, in case there were any differences, and I didn’t want to do things the “old” way.  So I created a file called myservice.svc with the contents:

<%@ ServiceHost Language="C#" Debug="true" Service="SomeService" %>

I then FTP’d to the folder which I set as an IIS virtual directory, and copied this svc file there.  Then I navigated to this folder in a web browser.  Predictably:

Directory Listing Denied

This Virtual Directory does not allow contents to be listed.

Okay, so somehow I needed to give the appropriate permissions.  From experience, I know that if you set global execute permissions using your FTP client, you can make the directory viewable to anyone browsing to it in a web browser, but I was pretty sure this was something different… perhaps an IIS setting.  So, back to my web host control panel I went, and look what I saw:

image

Sounds promising.  Sure enough, after clicking that option, I was able to browse all my directories and set “Browsing On” for whichever I chose.  I then browsed to this folder using a web browser.  I expected it to somehow run the service, then throw up an expected error saying that it couldn’t find it.  Instead, I got a directory listing with a single file: myservice.svc.  @#$%.  I don’t want people to actually be able to browse my svc file.  I want it to actually be run.  So I disabled browsing on that folder.  Strike 1. 

Alright, I saw another option that looks just vague enough to be promising:

image

Maybe this would set a certain file to be considered a “.NET App”, and maybe run as such.  (I should have mentioned earlier that I had Google’d every step of this process and ran into several dead-ends, hence the need to even post this article-blog-entry.)  Google led me to believe that this was for running ASP.NET applications, but there was some hint that it applied to web services as well.  A WCF web service is a .NET application, technically, isn’t it?  At least, it’s run within one.  So choosing this option let me pick a folder to set as a .NET application.  This made little sense to me, because a folder is a folder, not an application.  But I assumed that IIS would intelligently look inside the folder for an applicable application.  So I choose my “myservice” folder and set it as an application.  Back to the web browser:

Directory Listing Denied

This Virtual Directory does not allow contents to be listed.

@#%$!!!!!

Okay okay, no sweat.  I will try to turn browsing on; because maybe it will work properly in conjunction with setting that folder as a .NET App.  WRONG.  It still browsed the folder, .svc and all.  Okay, I will try to give execute permissions to the actual directory via my FTP client:

Directory Listing Denied

This Virtual Directory does not allow contents to be listed.

At this point, I’m thinking to myself: “Wow, that would have been super swell if D-roc had actually explained the first thing about getting this set up in his article.”

Okay, maybe I’m going about this with some wrong assumptions.  I mean, who cares if I can’t browse the folder?  I shouldn’t be able to browse the folder anyway, right?  This web service isn’t even supposed to be accessed via a web browser; it’s supposed to be accessed via some other client app on a user’s PC.  So, I start thinking to myself: Visual Studio is cool enough not to require me to manually FTP a freakin’ svc file to my web server.  There should be a way within Visual Studio to do this.  Well, luckily enough, I have my Visual Studio Web Service project I had previously created.  And sure enough, if I right-click that project, I see a “Publish…” option.  So I chose that option, and it prompted me for the target location.  I entered: http://mydomain.com/myservice and chose the default options, and clicked Publish. 

Much to my amazement, it worked the first time!

Connecting to http://mydomain.com/myservice…
Publishing folder /...
Publishing folder bin...
========== Build: 2 succeeded or up-to-date, 0 failed, 0 skipped ==========
========== Publish: 1 succeeded, 0 failed, 0 skipped ==========

I verified that in fact there were files published to this location.  Okay, okay, that’s a first step!  Now I want to test this service, which, by the way, simply takes an input string and manipulates it in a simple way.  I had some trusty code at my disposal from an online tutorial involving using WCF for interprocess communication.  Even though that’s not what I was doing, I still needed to make a connection using a similar method (or so I assumed).

So, in short, my client needs to create a channel between itself and the server.  It can do this using the handy ChannelFactory class provided by WCF:

ChannelFactory<IMyService> httpFactory = new ChannelFactory<IMyService>(
            new BasicHttpBinding(),
            new EndpointAddress("http://mydomain.com:8000/MyService"));

IMyService httpProxy = httpFactory.CreateChannel();

So this is my client app.  It references a shared contracts library which defines IMyService.  In case you haven’t tell by now, I’ve replaced the real names of my things with fake ones, to protect my billion dollar ideas.  If you want a full explanation of my logic here, please refer to the tutorial I referenced earlier.  So, I figured that something would go wrong if I ran this code, so I did – just to get a taste of what this brand of failure looked like, so that I’d recognize it in the future.

When I ran the test client, the handy built-in Visual Studio service host launched.  This was a bit disconcerting, since the ServiceHost I care about is the one allegedly hosted on my web server, so I didn’t want the local one to interfere.  But I carried on.  To my not-so-surprise, no exceptions were thrown when I called httpFactory.CreateChannel.  The real test would be the following line:

string translatedMessage = httpProxy.TwistMessage("I am a message.");

This code should actually connect to my service through my proxy, send it some message and get a string response, all handled for me.  Right?  I mean, I published my service already, so hopefully I can expect good things.  No such luck; I got an EndpointNotFoundException:

Could not connect to http://mydomain.com:8000/MyService. TCP error code 10060: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond xx.xxx.xx.xx:8000.

Okay, so let’s review my understanding: The endpoint is somewhere on the web server.  It’s part of the service, which is hosted by a ServiceHost.  But IIS manages the ServiceHost.  Somehow I need a ServiceHost running from IIS on my web server.  I already used the management tool to set a folder as an IIS .NET application (which, again, makes little sense because a folder is not any sort of executable as far as I know).  But wait, why did I use port 8000?  I just assumed that was proper, because I copied it from an example.  So let’s remove it and see what happens when I run the TestApp again, and attempt to call a service method from the proxy:

image

Progress!  Maybe!  Virtually clueless, I google’d this problem.  I found some forum posts with little help provided, but also this seemingly potentially helpful MSDN article.  In a cryptic way, the article explained – or so I believe – that I need to associate svc files with a certain DLL (aspnet_isapi.dll) in IIS.  It gave instructions about how to do this, of course working from the assumption that I am running IIS locally, which I, like hundreds of thousands of other people, are not.  No matter, there’s got to be an obvious way to accomplish the same thing in my web host.  Sure enough, something promising:

image

Clicking this link led me to an administration page where I could choose file extensions and the “program” (for lack of a better term) to execute them with.  I didn’t see the aspnet_isapi.dll listed explicitly, but I saw the option “ASP.NET”, which seemed to be close enough:

image

BAM!  After clicking Add, sure enough, the association was listed as: C:\WINDOWS\MICROSOFT.NET\FRAMEWORK\V2.0.50727\ASPNET_ISAPI.DLL.  Ladies and gentlemen, this is called “progress”.  Carelessly ignoring the potential warning about waiting 5 to 10 minutes, I ran my test app again:

image

Dang.  Well, I can wait the 5-10 minutes, but in the meantime I’m going to check the files published to my folder, since earlier I explicitly removed my old bogus svc file (assuming Visual Studio would be smart enough to create one for me when publishing).  Yep, it did.  The svc file is sitting there in the folder, sure enough.  Okay, I will wait… 

WAITED.  SAME ERROR.

Okay, let’s try a new angle: I’m going to connect to the svc file with the web browser:

Server Error in '/myservice’ Application.

Runtime Error

Description: An application error occurred on the server. The current custom error settings for this application prevent the details of the application error from being viewed remotely (for security reasons). It could, however, be viewed by browsers running on the local server machine.

Okay, I’ve had experience with this type of exception before, and it gave me instructions for getting specific details about the error message by modifying my web.config file:

<!-- Web.Config Configuration File -->

<configuration>
    <system.web>
        <customErrors mode="Off"/>
    </system.web>
</configuration>

So I’ll try this.  Nothing to lose.  I quickly discover that I don’t have a Web.Config, but I do have an App.Config.  Close enough, right?  It has a <configuration> group, so that’s probably the same, right?  BOOM, added.  Published.  Dang, no change.  Viewing the Web.Config in my app directory via FTP revealed that the customErrors tag was not added.  But wait, was I deceived?  My healthy skepticism of software brought my attention to a Publish dialog option.  Which one?

image

Choosing the “Delete all existing files prior to publishing” option made the customErrors tag propagate, and I was finally able to see the actual error:

[ArgumentException: This collection already contains an address with scheme http.  There can be at most one address per scheme in this collection.
Parameter name: item]

Oh my, look what we have here!!  After hours of struggling trying to learn how to host a WCF service in a shared hosting plan, I’ve finally reached the point where D-Roc’s tutorial, entitled “Hosting Wcf Services on a Shared Hosting Plan” begins!  Well hey, whaddya say we follow his instructions?

(Please refer to D-Roc’s tutorial for a walkthrough of this process.)

Now that I’ve completed the steps D-Roc described, I’m gonna try loading the svc file in a web browser again.  I don’t expect anything to work, since I’m not actually calling the service’s methods, but I just want to see what happens:

 

Server Error in '/myservice’ Application.


The resource cannot be found.

Description: HTTP 404. The resource you are looking for (or one of its dependencies) could have been removed, had its name changed, or is temporarily unavailable.  Please review the following URL and make sure that it is spelled correctly.

Eh, that’s not the first thing I expected, but I’m going to assume that there’s just some dependency of the service that can’t be loaded considering I’m like… not properly connecting to the service.  Shaky reasoning, I know, but really, what would I expect to happen if I connected in this unorthodox way?

Anyway, if I recall, I had a test app that I was playing around with.  Let’s see if my recent changes made any difference regarding the problem I was having.  I ran it and….

image

Ugh, kill me.  Alright, I Google’d some more and found that someone had had a similar issue, and solved their problem by changing their endpoint address to actually point to the svc file rather than just the virtual directory.  In plain English, instead of:

ChannelFactory<IMyService> httpFactory = new ChannelFactory<IMyService>(
            new BasicHttpBinding(),
            new EndpointAddress(http://mydomain.com/MyService/));

I should (maybe) write:

ChannelFactory<IMyService> httpFactory = new ChannelFactory<IMyService>(
            new BasicHttpBinding(),
            new EndpointAddress(http://mydomain.com/MyService/MyService.svc));

So I made this change and ran the test app.  Here is what I got:

ServiceActivationException was unhandled
The requested service, 'http://mydomain.com/MyService/MyService.svc' could not be activated. See the server's diagnostic trace logs for more information.

I DON’T HAVE ACCESS TO THE SERVER’S DIAGNOSTIC TRACE LOGS!  It’s a remote host!!

So at this point, I’m thinking I was better off without specifying the svc file in the endpoint address.  At least before I was getting an exception that seemed to imply that my service was being contacted and my method request was being rejected.  This new exception makes it sound like my service isn’t even executing.

So, by now you must be anxiously awaiting my resolution to this problem.  Unfortunately, I haven’t come across one yet!  I will have to leave you in suspense until I actually figure out how the heck to get this thing working properly.  (Hint: I will ask D-Roc to tell me what the @#$% he did.)

Update: It turns out that my custom factory created from D-Roc’s tutorial was actually expecting the service to be accessed via “www.mydomain.com” rather than “mydomain.com”.  Here’s the tiny change I had to make:

ChannelFactory<IMyService> httpFactory = new ChannelFactory<IMyService>(
            new BasicHttpBinding(),
            new EndpointAddress(http://www.mydomain.com/MyService/MyService.svc));

But then, when running the test client and calling my service method on the proxy, I got a ProtocolException: Content Type text/xml; charset=utf-8 was not supported by service…  To fix this, I needed to change BasicHttpBinding to WSHttpBinding, like this:

ChannelFactory<IMyService> httpFactory = new ChannelFactory<IMyService>(
            new WSHttpBinding(),
            new EndpointAddress(http://mydomain.com/MyService/MyService.svc));

Thanks to this article for explaining this.

Update 2: I found it quite odd that a Visual Studio 2008 Web Service project item wouldn’t create an svc file within the project.  Instead, it would generate a generic one automatically every time I published my service (via Visual Studio’s Publish… option).  But, as it turns out, if I manually add an svc file into the project, it will publish that one instead, and won’t generate one on its own.  The more you know.

After all this headache, my web service finally ran.  I feel much smarter now.  Oh, and to put things in perspective, all of these struggles I’ve encountered are still much less of a headache than the iPhone development experience.

Monday, March 2, 2009

Another user experience brought to you by Microsoft

Just so I’m not accused of being biased in favor of Microsoft, let me bring you an example of the user experience we’ve all come to expect from this company.

So today, looking to expand my budding WPF knowledge by working on a Silverlight application, I decided to download the Silverlight 2 Toolkit from MSDN.  Easy enough, right?  Not quite.  Here is a summary of my experience:

1. Visited http://msdn.microsoft.com.  Conveniently, there was a link on the left pane of the web site labeled Silverlight, so I clicked on this and it led to a page that pointed me in the right direction to install “Microsoft® Silverlight™ Tools for Visual Studio 2008 SP1”.  Now, I assume that I have VS2008 SP1 installed.  I mean, if I didn’t, it would have shown up in Microsoft Update, right?  So I ran the installer.

2. Oops!

image

I guess I didn’t have it installed.  Weird, I was sure I keep my computer up-to-date with Windows Update.  No worries, I just clicked the link as provided and it conveniently took me to the installer for VS2008 SP1. 

3. I downloaded SP1 and ran the installer.  Uh oh, another problem:

image

Ah well, I guess I have to run some program to clean up the beta I installed a while ago.  So I clicked the link, downloaded and ran the installer.  Then I ran the SP1 update.  Then I ran the Silverlight 2 installer.  I have to wonder why this couldn’t have been done for me somehow.

Now let’s pretend that I’m not Vargo.  I’m another user who attempts to solve the problem another reasonable way.  Instead of clicking the first link to download VS2008 SP1, I go to Windows Update to look for the update.  I see nothing.  So I open Visual Studio and select Help->Check For Updates.  This can’t fail, right?  Wrong.  Not only does it take me to the same Windows Update site which failed me previously, but it opens it in my default browser: Firefox, and I get an error stating that I need to load the Windows Update site in Internet Explorer in order to get it to work!  MSN—no, sorry—“Windows Live” Messenger has no qualms about annoying me by opening hyperlinks in my non-default browser; why can’t Visual Studio do the same thing when it’s actually necessary!

Microsoft really has some work to do when it comes to the user experience.  But I’m not really shocking anyone here.

Monday, January 26, 2009

The Poor Man’s Stock Quote Web Service

Ever wanted to programmatically fetch stock quotes? Ever look into it? I did. StrikeIron charges top dollar for their stock quote service, and, frankly, I don’t have that kind of money. But I can always go to finance.yahoo.com, and get the same information for free. Let’s exploit that, let’s create The Poor Man’s Stock Quote Web Service.

See it in action!

Using Windows Communication Foundation (Wcf), we will build a web service that takes a ticker symbol for a stock, grabs the text from the yahoo finance webpage, parses out the relevant stock quote information, and then returns a sweet StockQuote struct full of information. The legality of all this in a commercial application could probably be put to question, but we’ll leave that as an exercise for the reader.

Building a Wcf Service is very straightforward, and the source linked at the bottom is a Wcf sample perfect to introduce you to Wcf. This article isn’t an intro to Wcf, but if you’re quick, which I’m sure you are, you could pick it all up from the sample. See my other blog post to see how to host a Wcf service on a shared hosting plan.

First, we must define the ServiceContract for our Wcf Service:

[ServiceContract]    
public interface IStockQuoteService    
{    
    [OperationContract]    
    StockQuote GetQuote(string ticker);    
    [OperationContract]    
    List<StockQuote> GetQuotes(string[] tickers);    
}

As mentioned earlier, I’m going to use the Yahoo Finance to provide information for my Stock Quotes. Thus, the YahooStockService was born:

/// <summary>    
/// The Stock Quote Web Service that scrapes values from Yahoo's finance stock page.    
/// </summary>

[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]    
public class YahooStockService : IStockQuoteService

In our Wcf service, we programmatically grab the text from a website using the HtmlScraper.GetPageContent function:

public static string GetPageContent(string url)    
{    
    WebRequest wreq = HttpWebRequest.Create(url);    
    WebResponse wres = wreq.GetResponse();    
    StreamReader sr = new StreamReader(wres.GetResponseStream());    
    string content = sr.ReadToEnd();    
    sr.Close();

    return content;    
}

Now that we have the page’s text, we can clumsily parse the text for the value that prefixes the content we are looking for. I usually break in my debugger, grab the Html page’s string value from the Watch window, and paste it in notepad. Then I look for the company name, and copy whatever’s in front of it.

Here is a simple example of the YahooStockService parsing for the Company Name:

private string ParseCompanyName(string page)    
{    
    // Regex pattern pasted from Html page.    
    Regex parseFor = new Regex("<div class=\"yfi_quote_summary\"><div class=\"hd\"><h1>");    
    return HtmlScraper.ParseContent(page, parseFor, "</h1>");    
}       


And now here’s the source. Many other parse functions exist in the sample, and we eventually end up with all the stock information we could need. Now go forth, poor one, and gather stock information to your heart’s content. At the time of this writing, it’s probably all going down anyways. GGgggooooo Bailout!

One note about the sample: it uses a Silverlight web app to consume the Wcf Service, you might need to install the Silverlight SDK.

References: Building a Web Service to Provide Real-Time Stock Quotes

Objective-C versus C#, part 2: Loading, rotating, and saving an image

 

In this example, I’ll compare Objective-C/Cocoa Touch to C#/.NET in their ability to load an image from a file, rotate it 90 degrees, and then save the modified image.  Both platforms are perfectly capable of performing this task.  One of them, however, sucks orders of magnitude less.  I’ll leave it as an exercise to the reader to decide to which I’m referring.  I’ll list the C# example first this time, since I wouldn’t want to be accused of favoritism.  In fairness, I should point out that for the Objective-C version, I cut some corners.  By using a UIImageView to house the image, I saved many lines of code that would result from applying transforms to the graphics context directly.

C#/.NET

Image myImage = Image.FromFile(@"c:\myImage.png");
myImage.RotateFlip(RotateFlipType.Rotate90FlipNone);
myImage.Save(@"c:\newImage.png");

Objective-C/Cocoa Touch

UIImage* myImage = [UIImage imageNamed:@"myImage.png"];
UIImageView* imageView = [[UIImageView alloc] initWithImage:myImage];
[imageView setTransform:CGAffineTransformMakeRotation(M_PI / 2.0)];

CGSize newImageSize = CGSizeMake(myImage.size.y, myImage.size.x);
UIGraphicsBeginImageContext(newImageSize);
[imageView.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage* newImage = [UIGraphicsGetImageFromCurrentImageContext() retain];
UIGraphicsEndImageContext();

[UIImagePNGRepresentation(newImage) writeToFile:@"myNewImage.png" atomically:YES];

[imageView release];
[newImage release];

Sunday, January 18, 2009

Objective-C versus C#, part 1: Searching for a substring within a string

 

I’ve been wanting to create a series of comparisons between the syntax of Objective-C and C#.  I’ve been writing a lot of both these days, so I have a lot of experience with each.  For our first example, let’s say we wanted to check for a substring within a string:

Objective-C

if ([myString rangeOfString:@"mySubstring"].location == NSNotFound)) {
   NSLog(@"mySubstring not found in myString: %@", myString);
}

I don’t know how you could get any more intuitive than that, but just for kicks let’s look at the C# equivalent:

C#

if (!myString.Contains(“mySubstring”))
{
    Console.WriteLine(“mySubstring not found in myString: “ + myString);
}

Monday, January 12, 2009

The Science of Debugging

One of the best pieces of advice I ever received about debugging code was something that I could have just as easily brushed aside.  I was attending a work-sponsored training course, and the instructor said something that struck me as obvious and profound at the same time: Always start with a hypothesis.

How many times have you found yourself chasing down a bug, clueless about its cause, blindly adding variables to your watch window (or for XCode Objective-C programmers, blindly opening up the console window and typing “print object.property” – no, wait, that common syntax isn’t supported by the debugger.  So you type “print [object property]”, then receive an error that it can’t determine what the type is without a cast, even though it’s just an integer, so you type “print (int)[object property]”) without really knowing what you’re looking for?  As you step through the code aimlessly, you finally realize that you’ve jumped past the part of the code which reproduced the bug, and you have to start over.  (This situation is magnified by the lateness of the hour and the length of time you’ve been coding prior.)

You repeat this process several times, gradually locking down more and more of your code until you’re picking it apart one line at a time.  But even this doesn’t help if you don’t know what you’re looking for.  But that’s just it – you don’t know what you’re looking for.  If you did, you wouldn’t need to be debugging in the first place. 

Rather than spinning your wheels, you need to come up with a hypothesis; an educated guess about what might be causing the behavior you’re seeing.  If a dialog isn’t appearing on the screen, a simple hypothesis might be:

The code which spawns the dialog is not being executed. 

Testing this hypothesis is simple; just set a breakpoint on the line of code responsible for displaying the dialog (assuming you find it – maybe that was the problem), run your program, and observe whether or not it’s hit.  If it’s hit and the dialog still doesn’t appear, that’s fine – great, even.  You’ve gained information about the situation.  Rather than going on a wild goose chase, you’ve narrowed down the issue.  Now you can test another hypothesis:

The dialog’s Visible property is set to false.

Failing that, try another:

The dialog’s bounds are outside of the screen’s bounds.

And other:

The dialog is rendering underneath another window of the application.

The key is that you’re learning more about the situation with every hypothesis, rather than repeating the same guesses, moving off in random directions based on hunches, and becoming more confused and frustrated.

Note that all of these hypotheses are testable and falsifiable.  That is, you can objectively demonstrate if the hypothesis is true or false through experimentation.  This is crucial not only in debugging but for science as a whole.  There’s a reason why Intelligent Design Theory is the butt of jokes; there’s nothing testable or falsifiable about the idea that the universe was created by (essentially) magic.  Science, on the other hand, gains from both confirmed and falsified hypotheses (a fact which is lost on evolution-deniers).  Just as science gains knowledge about the universe from a disproven hypothesis, you gain knowledge about your application the same way.

Obvious, right?  When you’re tracking down a frustratingly elusive bug while exhausted and over-caffeinated, it isn’t. 

Sunday, January 4, 2009

Using the PollingDuplexHttpBinding for a Silverlight Group Chat

1) A Quick Intro to the PollingDuplexHttpBinding

Comet technologies, such as AJAX push and HTTP server push, allow web pages to have data pushed to them from the server, rather than always having the client pull information. It mimics this feature by having the browser poll the server at regular but short intervals (~1 second) to check for updates. Now web pages can be updated dynamically without any user input. Lucky for us, Silverlight supports this using the PollingDuplexHttpBinding Wcf Binding, which does most of the heavy lifting.

In this article, we hope to build a basic Silverlight group chat application by connecting a PollingDuplexHttpBinding to a Wcf Service hosted on a shared hosting plan.

There are excellent introductory articles to this technology that are pretty much required reading if unfamiliar with the PollingDuplexHttpBinding (Skim the first link if pressed for time):

  1. Basketball score server by Dan Wahlin
  2. Stock quote server by Peter McGrattan

The bulk of the PollingDuplexHttpBinding functionality is covered in the blogs listed above. From here on out, I will talk about some of the higher level details involved in making the simple chat program on top of the PushDataReceiver.

2) The static list of clients.

Every time a client connects to our webservice, we instantiate a new instance of the GameStreamClient class and keep it in a static List<ChatClient>. This does restrict us to only being able to run our chat server on one appdomain.

private static List<IGameStreamClient> clients = new List<IGameStreamClient>();

Our service gets instantiated on a Per Session basis as shown by the mark up below. In retrospect, I actually think it should have been a singleton, but that's for another time.

[ServiceBehavior(InstanceContextMode =
    InstanceContextMode.PerSession,ConcurrencyMode = ConcurrencyMode.Single,AutomaticSessionShutdown = true)]


3) The inactivity timeout and the stay alive ping.

Each Wcf connection has an inactivity timeout that defaults to around 10 minutes. We want our clients to be able to idle in the chat room, and not get booted for inactivity. Here we introduce a stay alive packet to reset this inactivity timeout. The end user will know nothing of it, and this way they can idle all they want.

Message gameDataMsg =
    Message.CreateMessage(MessageVersion.Soap11,"Silverlight/IGameStreamService/Receive","stayalive");

gameDataMsg.Properties.Add("Type", "StayAlive");

this.localClient.BeginReceive(gameDataMsg, EndSend, this.localClient);

4) I remove when I catch an exception when sending to a client.

With the PollingDuplexHttpBinding, the only way we will know if a client disconnects, is when the server fails to deliver a message. We cannot rely on the client to tell us when they are disconnecting, especially when considering that they are connecting from a browser; there's no real way to elegantly close out the client. Plus, they could just crash. As a result, there is no real disconnect, there is more of a send failure mechanism, that removes clients from the static list of ChatClients. In the proceeding ChatMessage broadcast, any clients that throw a CommunicationException/TimeoutException are removed from the server's client list. These timeouts could block the server however, so we must handle this asynchronously so as not to penalize connected clients.

foreach (IGameStreamClient client in clients)
{
    try
    {
        //Send data to the client
        if (client != null)
        {
            Message gameDataMsg =
                Message.CreateMessage(MessageVersion.Soap11,"Silverlight/IGameStreamService/Receive",data,this.serializer);

            gameDataMsg.Headers.Add(MessageHeader.CreateHeader("Type", "", "DataWrapper"));
            client.BeginReceive(gameDataMsg, EndSend, client);
        }
    }
    catch (Exception ex)
    {
        // Exception caught when trying to send message to client so remove them from client list.
        // Should probably catch a more specific exception but I'll leave that as an exercise for the reader.
        clientsToRemove.Add(client);
    }
}
foreach (IGameStreamClient client in clientsToRemove)
{
    clients.Remove(client);
}


5) Using DataContracts and DataContractSerializers to send complex types.

Sending strings back and forth is not really fun. Complex types such as structs would allow for much richer data transfer. So it's a good thing Wcf supports DataContracts and has a DataContractSerializer that makes this process seemless.

private readonly DataContractSerializer serializer = new DataContractSerializer(typeof(ChatData));
// Serialize
Message
gameDataMsg =
    Message.CreateMessage(MessageVersion.Soap11,"Silverlight/IGameStreamService/Receive",chatData,this.serializer);

// Deserialize
ChatData
chatData = receivedMessage.GetBody<ChatData>(this.serializer);


6) Adding Header information to the Message object so the Processor can serialize to the appropriate type.

When your application gorws in complexity, you will probably have multiple DataContracts, but your Wcf Callback contract will only have one message handler, and you will need to programmatically handle the Message Body. To know what that body is so you can deserialize it, the sample tags the outgoing message with type strings in the Headers. This acts as a form of metadata for the message and allows the caller to deserialize the DataContract to the message of the passed type, allowing proper complexity to the callback contract. This is a lot better than clumsily having a class with a body and a type, and dealing with deserialization logic yourself.

//Server creates the message and tags it with a type.
Message gameDataMsg =
    Message.CreateMessage(MessageVersion.Soap11,"Silverlight/IGameStreamService/Receive","stayalive");

gameDataMsg.Properties.Add("Type", "StayAlive");

// Receiver parses the message type and deserializes using the correct deserializer.
// Check message type
string type = string.Empty;
for (int i = 0; i < receivedMessage.Headers.Count; i++)
{
    if (receivedMessage.Headers[i].Name == "Type")
    {
        type = receivedMessage.Headers.GetHeader<string>(i);
        break;
    }
}
// Dispatch message based on type.
switch (type)
{
    case "StayAlive":
    break;
    case "DataWrapper":


7) Source code.

Source code

Hosting Wcf Services on a Shared Hosting Plan

Hosting Wcf Services on a windows shared hosting plan has one issue that people should be aware of: You can only add one address per scheme to a service host. But what does this mean?

Shared hosting plans often run with the default IIS set up, which means that there are two addresses to your site: http://www.yourdomain.com and http://yourdomain.com. Wcf only allows one address of any scheme (ie http://) to be used as a Service host, but by default, it tries to add the two. If you would try to run a web service using this markup,

<%@ ServiceHost Language="C#" Debug="true" Service="SomeService" %>

You would receive the following error:

This collection already contains an address with scheme http.  There can be at most one address per scheme in this collection.

To get around this, you'll have to make a custom ServiceHostFactory that will select only one address, and have your markup use this custom factory with the 'Factory' attribute. Which address you prefer is up to you, just remember to use it in your Endpoint configurations!

.svc file:

<%@ ServiceHost Language="C#" Debug="true" Service="SomeService" Factory="SomeNamspace.AddressSelectorHostFactory" %>

   
 

AddressSelectorHostFactory.cs file:

public class AddressSelectorHostFactory : ServiceHostFactory
{
    protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
    {
        // When hosting on a shared hosting plan, the default IIS configuration passes 2 addresses
        // to CreateServiceHost: http://www.yoururl.com and http://yoururl.com.
        //
        // You can only add ONE address of a certain scheme (ie: http://), so we just take the www address.

        
if (baseAddresses.Length > 1)
        {
            Uri address = (from u in baseAddresses where u.AbsoluteUri.StartsWith("http://www.") select u).First();
            return new ServiceHost(serviceType, address);
        }
        else
        
{
            return new ServiceHost(serviceType, baseAddresses[0]);
        }
    }
}

 
 

More about this can be read here.