advanced web statistics

External URLs and Phone Numbers in WP7 WebBrowser Control

The Windows Phone 7 WebBrowser is garbage.  F**king horrible. If you want to display basic HTML it's great.  If you want to display HTML that users can interact with (i.e. clicking hyperlinks, mailto: links, or dial phone numbers) it's basically useless.  Don't even get me started on opacity and background images.  In developing a Windows Phone 7 application recently there was a need to link to a mobile-enabled website. In said website there were pages with phone numbers, email addresses, etc... A business requirement for the application was to open up the mail client, dial a phone number, or open a hyperlink when a user clicked on these links.  No duh right?  I thought the WebBrowser would at least be able to parse out links with href and mailto and since it's built for a PHONE it should be smart enough to detect tel.  Fail.

At this point we had a couple of options (Mango is NOT an option at this point):
  1. Recreate the external site in XAML with event handlers for the "hyperlinks" which would end up being styled textblock controls
  2. Take a screenshot of the mobile site and place rectangles over the hyperlinks and wire those up to events
  3. Download the HTML from the site asynchronously, parse HTML and find head or title tags, inject JavaScript to find and enumerate all a tags and wire up an onclick event to raise the ScriptNotify event [via window.external.Notify], call the WebBrowser's NavigateToString method and pass in this newly-constructed HTML, figure out what kind of link was clicked and then fire an appropriate task
Before I talk about which option I chose, take a minute to soak in the absurdity of the aforementioned solutions (FYI - I chose 3). Take this simple example site here:

simple webbrowser example 1

And here's the markup (unadulterated)

simple webbrowser example 2

Simple enough right? You can clearly see that the links are sporting the correct syntax. Time to start hacking.

The first thing we need to do is add JavaScript to get all of our a tags. Once we have this we simply need to enumerate and attach an onclick event. I'm not a JavaScript expert by any means but think this fairly unobtrusive. This JavaScript is going to remain constant so we should use the const string:

simple webbrowser example 3

The next thing we need to do is wire up the WebBrowser control. The most important part is to enable scripting via the IsScriptEnabled property. This is set to false by default and resulted in many f-bombs being dropped until I figured this out. We will also need to wire up the ScriptNotify event. This is how the WebBrowser will communicate with our application.

simple webbrowser example 4

In the LoadedComplete method we perform an asynchronous request via WebClient object to get the source HTML from the server. We then create a StringBuilder instance and insert our JavaScript just before the </title> tag.

Now that the ScriptNotify event is wired up we can set a breakpoint in our code, run the application, and determine which link was clicked when we tap the link.

simple webbrowser example 5

In the case above, we'll want to launch the EmailComposeTask.

simple webbrowser example 6

Running this code in the emulator and we get the following:

simple webbrowser example 7

I don't have a mail account setup in the emulator (is this possible?) so we see the fail message. But if I did in fact have an email account setup it would display appropriately. For other scenarios you would use the appropriate phone task.

Easy enough. This code isn't production-ready by any means. I just wanted to quickly share with others how to accomplish a task that should be a native experience (IMO). I will clean this up and add logic for things such as detecting if there is actually a title tag, confirming that a task is about to be shown, cleaning up the ScriptNotify event handler, etc... This would take about 3 seconds using Interface Builder in Mac OS (iOS development). iOS developers have the luxury of checking boxes for detecting various links in text controls.

Original inspiration: Integrated Links and Styling for Windows Phone 7 WebBrowser Control

kick it on DotNetKicks.com

Json.NET and Generic HttpWebRequest Responses FTW

Working on a Windows Phone 7 mobile app recently, I found myself writing a bunch of similar / redundant code for HttpWebRequest response handling. By "a bunch" I mean in the neighborhood of 3 methods.... Hello Generics!!!

If I find myself writing the same handler more than once and the only difference is the type of object I am returning I ALWAYS (at least try to) write a generic method to take care of the heavy lifting.  There are a plethora of reasons to use Generics when the opportunity presents itself and I'm not going to start listing them.  Those of you that understand .NET Generics will get it.  If you are a .NET developer and currently developing applications targeting version 2.0 or greater and aren't familiar with Generics, then I highly suggest you educate yourself: Generics in the .NET Framework.

If you are still with me and are familiar with the System.Net namespace and the HttpWebRequest class (as it pertains to Silverlight and/or Windows Phone 7), I'd like to share the following response handler for dealing with Asynchronous requests:

private static T ProcessFamiliarRequestResponse<T>(IAsyncResult asyncResult)
{
    HttpWebRequest request = (HttpWebRequest)asyncResult.AsyncState;
    HttpWebResponse httpWebResponse = (HttpWebResponse)request.EndGetResponse(asyncResult);

    using (StreamReader streamReader = new StreamReader(httpWebResponse.GetResponseStream()))
    {
        return JsonWorker.TooEasyToDeserializeJsonObject<T>(streamReader.ReadToEnd());
    }
}

If this doesn't make sense to you I highly suggest reading up on WebClient and HttpWebRequest usage.  If you are familiar, I hope you can appreciate that this is one point of entry into handling an infinite number of requests (within reason).

It gets cleaner: Enter Json.NET.  Personally, I like to create clean POCO's to return data to the consumer.  I have seen way too many examples creating objects that conform EXACTLY to the Json format returned from any given request.  For instance:

public class Employee
{
    public string employee_first_name { get; set; }
    public string employee_last_name { get; set; }
    public string employee_job_description { get; set; }
}

Gross (imo).  .NET is so much better than this.  I take pride in the code that I deliver and personally believe the following class is much cleaner (and not to mention, conforms to .NET naming conventions):

public class Employee
{
    [JsonProperty("employee_first_name")]
    public string FirstName { get; set; }

    [JsonProperty("employee_last_name")]
    public string LastName { get; set; }

    [JsonProperty("employee_job_description")]
    public string JobDescription { get; set; }
}

This way you can map your neatly-defined POCO properties to their disgusting origins.  The following generic method for deserializing your Json results works fairly well (pre-supposing you decorated your POCO(s) with the JsonProperty attribute OR left it repulsive and/or primitive):

public static class JsonWorker
{
    public static T DeserializeJsonObject<T>(string result)
    {
        return JsonConvert.DeserializeObject<T>(result);
    }
}

If you want to take it a step further, you could add the following method to your JsonWorker class to serialize your objects. Think storing application state in IsolatedStorage or updating your light-weight, client-side database (via Sterling (which is AWESOME!!!)):

public static string WayEasierToSerializeObjectToJson(object randomPOCO)
{
    return JsonConvert.SerializeObject(randomPOCO);
}

Easy.

kick it on DotNetKicks.com

Debug a Windows Phone 7 Application After a Tombstone

In debugging a Windows Phone 7 issue related to application state and tombstoning recently, I found that the Visual Studio debugger stops after the application comes back from a tombstone (press the Windows putton on Windows Phone 7 emulator, then press device back button to reactivate the application).  A quick Google search and I ran across a little gem on Shawn Wildermuth's blog.

Solution:  Press F5 again while the emulator is displaying the "Resuming...." progress indicator. 

Easy.

kick it on DotNetKicks.com

Set Silverlight Startup Page

In sandboxing Windows Phone 7 recently I came across the need to change my startup page.  The reasoning for this is simple: I have a core of the work completed and I want to sandbox a data call before I implement in the actual application.  With conventional web projects this is as easy as right-clicking the file you want to and click 'Set As Start Page'. With the Windows Phone 7 SDK this luxury does not exist.

There is however a way to accomplish this with a little bit of code.  Simply open up your projects App.xaml.cs and implement an Application_Startup method.

private void Application_Startup(object sender, StartupEventArgs e)
{
    RootVisual = new SandboxPage();
}

SandboxPage is the name of my XAML page in this example. Here we simply set the RootVisual to an instance of our new page.

The second piece to this is registering this startup method in the App constructor a la:

public App()
{
    Startup += Application_Startup;
}

This doesn't necessarily apply to Windows Phone 7.  General Silverlight.

Easy.

kick it on DotNetKicks.com

Hello Windows Phone

Today the Community Technology Preview release of Visual Studio 2010 Express for Windows Phone 7 was released. For those not in the know, this release provides 100% compatibility with the final version of Visual Studio 2010.

You can get it here: Visual Studio 2010 Express for Windows Phone 7

I have been interested in and writing XNA for a couple of months now and will start posting more regularly thanks to this new addition.

Stay tuned!

kick it on DotNetKicks.com

Dynamically Insert Language ISO Code in Sitecore Url

In working with localizing a Sitecore CMS solution recently I came across an interesting requirement: analytics (SEO optimization by region).  I was handling Sitecore localization by adding supported languages and creating localized versions of each content item.  The wrinkle was that I needed to now add a language prefix to all the urls on the site so they could get indexed appropriately for each region.  To make it even more complicated, I had to deal with hard-coded urls that weren't driven by the CMS.  I thought I was going to have to create multiple sites within Sitecore for each language, duplicate content, etc...  It turns out that it was much easier than this.

In a Sitecore web.config you'll find a linkManager section. This will handle much of the heavy lifting for you. There is one setting that you need to pay attention to (2 if you aren't using IIS 7).

The first (and most important) is the languageEmbedding setting. In a site that is in one language you should set to "never". A site that may have one or two localized pages here and there set to "asNeeded". In my case, a full-blown localization effort, this should be set to "always".

If you aren't using IIS 7 you will need to set the setting for addAspxExtension to "true".

    <linkManager defaultProvider="sitecore">
      <providers>
        <clear />     
          <add name="sitecore" type="Sitecore.Links.LinkProvider, Sitecore.Kernel"
          addAspxExtension="true"
          alwaysIncludeServerUrl="false"
          encodeNames="true"
          languageEmbedding="always"
          languageLocation="filePath"
          shortenUrls="true"
          useDisplayName="false" />
      </providers>
    </linkManager>

Sitecore CMS will now take care of the url rewriting!  Easy.

For those you like me that have pre-defined navigation requirements (i.e. not driven 100% by the CMS) there is one more step to take to accomplish url prefixing.  Take a link such as:

<a href="/Foo.aspx">

To get a url that looks like http://www.foo.com/de-DE/foo.aspx you simply need to write a little bit of "yellow code".

<a href="/<%= Sitecore.Context.Language %>/foo.aspx">

Easy.

kick it on DotNetKicks.com

Problem Deploying MVC Applications on IIS 5.1 or IIS 6?

I know what you are thinking, "Who uses IIS 5.1 or IIS 6 these days?"  Believe it or not, some environments still use these and I had been pulling my hair out trying to deploy an MVC application to an IIS 5.1 server. The application works in production and wasn't working locally. Nothing had changed aside from some minor View refactoring. A couple of hours later I thought back to an Ektron project that required URL-rerouting and then it dawned on me: "IIS is checking to make sure that the file exists".

I opened up IIS, drilled down to my application, and followed these steps:

  1. Right-click application (or virtual directory)
  2. Click 'Properties'
  3. Click 'Home Directory' if application ('Virtual Directory' if virtual directory)
  4. Click 'Configuration' button
  5. Click 'Add' button
  6. Executable: C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll
  7. Extension: .*
  8. Check 'All Verbs' if it isn't already (it should be)
  9. Uncheck 'Check file exists'
  10. Click 'OK'
  11. Click 'Apply'
  12. Click 'OK'
Dear Diary. Jackpot.

kick it on DotNetKicks.com

jQuery Data Method is the Business

<3 this little jQuery gem

$(document).ready(function() {
    $('#button').data('Data', { Message: 'sup foo?', Email: 'asdf@asdf.com' });

    $('#button').click(function() {
         var data = $(this).data('Data');
         alert(data.Message + '\n' + data.Email);
    });
});

<input type="button" id="button" value="clickie" />

jQuery data() method result

Easy.

kick it on DotNetKicks.com

Generic jQuery Function to Remove CSS Classes

I've been using a lot of jQuery lately in a new project and am falling in love with it!  It is a wonder why I have never used it before but am glad I was kind of forced to learn it ;)

As with anything new there is a bit of a learning curve.  The application I am working on boasts a large number of tabs for different sections of the site.  One of the requirements is to toggle the "active" tab via CSS class.  Easy right?  This was easy to do in vanilla JavaScript so it should be super-easy to do with jQuery.  It is!

$('#FooItem1').removeClass('active');
$(
'#FooItem2').removeClass('active');
$(
'#FooItem3').removeClass('active');
$(
'#FooItem4').removeClass('active');
$(
'#FooItem5').removeClass('active');

That works great but there is one caveat: adding new tabs.  If the requirements of the UI changed and we were to have to add a new tab (or 6 more) then we would have to not only change the view (or in this case partial view ;) ) but also the JavaScript functions dealing with these tabs.  Since all of our tabs are UL with stylized LI's containing anchor tags I decided to create something like this:

function RemoveActiveClassFromListItemControlByID(controlID) {
   $(
"#" + controlID).children().each(function() {
   $(
this).children("a").removeClass("active");});
}

Now this isn't that generic since I have the "a" and "active" strings hard-coded.  In this case it works for us since all the tabs are the same format and all we really need is the id of the control.  This little function will enumerate the children of the control (in this case all LI's and then enumerate the A children and remove the active css class.  Simple.  To extend this to be even more generic you could do the following:

function RemoveClassNamesFromChildElementByControlID(controlID, childElement, className) {
$(
"#" + controlID).children().each(function() {
   $(
this).children(childElement).removeClass(className);});
}

Here's an example of how you could use the function above.  Let's say that you want to enumerate all children in a OL with an id of "fooList". Each children has a span tag with a css class of BAR and you want to reset all of them when a user clicks on a hyperlink.  This would be extremely simple:

<a href="javascript:(RemoveClassNamesFromChildElementByControlID('fooList', 'span', 'BAR'));">CLICK HERE</a>

Easy.  I'm really starting to love this jQuery business.

jQuery + MVC = love

kick it on DotNetKicks.com

SQL Server 2008 Save Not Permitted Dialog Box

I was creating some tables this evening in a SQL Server 2008 database this evening so that I could sandbox some MVC functionality for a current project.  I had designed the tables according to the tutorial only to find out that this wasn't the case.  I'll just log back in to SQL and make the necessary changes.  Easy.

When I added the missing column I went ahead and reordered to match the same order of the tutorial because, well; I am a little OCD at times.  I remember doing this in the past pre-SQL 2008 with no trouble.  This time I was hit with this:

Weird.  Again, I had never seen this before so I was a bit surprised.

According to SQL Server 2008 Books Online this can be caused by any of the following:

  1. Adding a new column to the middle of the table
  2. Dropping a column
  3. Changing column nullability
  4. Changing the order of the columns
  5. Changing the data type of a column

Really?  These all seem like fairly common tasks when working within a database.  As odd as this may seem (maybe there is a good reason for this?), there is a very easy fix.

From the Tools menu click on Options, expand Designers, click on Table and Database Designers.  Select or clear the Prevent saving changes that require table re-creation option.

Much better.  Back to work.

kick it on DotNetKicks.com

<< Newer Entries Older Entries >>