Posted by: lluppes | December 8, 2013

MVC5 Authentication Roles Failure

I’ve been doing a lot of work lately with ASP.NET MVC5, and with most of my development being in a corporate environment, we almost always need authentication in our projects.  MVC4 introduced a new authentication model and MVC5 made major changes to the authentication model once again.

In a recent project, I was vexed with a very strange error that took me hours to resolve.  On my development machine, I have SQL Server installed, but do NOT have SQL Express installed or running.   Some of my other MVC5 projects were working just fine with Authentication and Roles.  In this particular project, the authentication was working just fine, and was creating users in the database as they authenticated.  However, as soon as you tried to check a role using either the explicit Roles.IsUserInRole method or through a standard MVC decoration like [Authorize(Roles = Constants.Role.AdminRole)], the page would sit and spin several minutes, then time out with this error.

A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: SQL Network Interfaces, error: 26 – Error Locating Server/Instance Specified)
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
SQLExpress database file auto-creation error:   [stack trace – blah, blah, blah]
Version Information: Microsoft .NET Framework Version:4.0.30319; ASP.NET Version:4.0.30319.33440
Source Error: An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.

Apparently the Role Manager was attempting to create a SQL Express database in order to validate the roles, and it was unable to do so.  During my searching and experimenting, I found many red herring suggestions which did not help at all.  Since this project was using MVC5, the SimpleIdentity provider was NOT being used, as MVC5 uses the new AspNet.Identity libraries.  So most of the suggestions on this topic offered up things about SimpleIdentity, WebMatrix, adding a <RoleManager> or “enableSimpleMembership” tag in the web.config, update InitializeSimpleMembershipAttribute, etc. – and none of these worked.

Oddly enough, what did work did not seem at all intuitive to me:  removing the RoleManager in the web.config modules section.

<system.webServer>
  <modules>
    <remove name="RoleManager" />
  </modules>
</system.webServer>

This didn’t seem at all obvious to me since I had not actually added it, and I was not running in the context of a server which had a root web.config file which added it.  I still don’t know  how or why it was trying to load the older RoleManager.  In any case, adding this line allowed the MVC5 Role Manager to kick in and then everything worked fabulously.  As I’ve said – I’ve had other MVC5 projects which used Authentication and Roles and had no problems, but there was something different about this project which caused this failure.

I hope this helps someone else as this strange error cost me hours of down time.

Posted by: lluppes | June 26, 2013

The Inexpensive DIY Standing Desk

Last year I spent a lot of time working on my book, speaking at conferences, and working on this blog.  This year I’ve been focused a little more internally and haven’t written another book or signed up to speak at conferences.  I’ve spent a lot of time trying to get back into the shape that I was in several years ago (before middle age gave me my current round shape!)  I’ve been working out twice a week with a trainer, and playing racquetball two or three times a week, and it’s really helped me physically.

My latest effort to improve my health is to try out a standing desk. There are lots of articles out there on why standing up more is a good idea, such as these:

Sitting is Killing You (Medical Billing & Coding)

Sitting for Too Long Is Bad for Your Health (WebMD)

StandingDesk_RiskOfDeath

Image from Medical Billing and Coding Article

Assuming you are interested in trying this, it takes a lot of time and effort to purchase everything and set it up just to see if you like it or not, so I came up with a very quick and inexpensive temporary solution.  I’ve got a cubicle with enough space to keep my sitting computing area and put a stand-up area right beside it.  To get a feel for how I would like it, I built a temporary standing desk using copy paper boxes.

StandingDesk_0_CopyBoxes

StandingDesk_7_Sitting

Everybody’s got these kind of boxes around their office, so it’s a matter of just a few minutes to put some up on your desk and find the right height for you and give it a try.  Once you’ve done this for a few days and determined that this really does work for you, then you can move on to creating a nicer desk.

If you Google “standing desk Ikea”, you can find several people that have created simple standing desks for about $25 using Ikea Lack desk components, and those seem to work pretty well.  However, that didn’t exactly fit what I wanted, so I set out to building my own without spending too much money.  If you don’t want to go to the trouble of building it, the Ikea Lack desk is pretty simple, or you can just buy one like this on Amazon.

As I understand it, the two general ergonomic principles that you want to follow is that the top of your monitor should be just above eye level, and your keyboard should be at or just below your elbows so your arms are bent at about 90 degrees.  Since I have a cubicle wall with adjustable tracks built into it, it made sense for me to put a shelf up there to hold my monitors, then create a simple stand for my keyboard.

I went to my local Home Depot and picked up about $30 worth of materials: (similar products are available at any Home Depot, Menards, Lowes, etc.)

  • 1 – 12” x 48” Melamine Shelf – Monitor Shelf (~$8.50)
  • 2 – 12” Shelf Brackets (~$5.00)
  • 1 – 12” x 36” Melamine Shelf – Keyboard Stand Top (~$7.00)
  • 1 – 8” x 36” Melamine Shelf – Keyboard Stand Back (~$5.00)
  • 1 – 10” x 24” Melamine Shelf – Keyboard Stand Legs (~$4.50)
  • 4 – #8 1.5” screws ($1)
  • 9 – #8 1” screws ($1)

Start by cutting the 24” long shelf in half so you have two 12” boards that you use for legs.  I’m about 6 foot tall, and my normal desk is about 28.5” high, so this puts my keyboard at about 41” off the floor.  You’ll want to adjust this height to fit your frame.   If you’ve tried it out with temporary boxes, you should be able to measure it out and figure out how high your keyboard should be. If you have a table saw, split the back board so that you have a 1” x 36” strip that you can use for cleats, then cut 8” off each end of that 1” cleat board so you have three pieces. If not, you can buy a small piece of 1×2 to use for cleats – the only difference is that it won’t match exactly.

StandingDesk_1_Parts

Use a countersink (if you have one) and pre-drill holes and screw the legs to the back board.

StandingDesk_2_EndJoint

You should end up with something that looks like this:

StandingDesk_3_BackAssembly

Set the completed back board on the top of your keyboard shelf and mark out where the cleats should go, then screw the cleats to the bottom of the top board.  If you’ve got a countersink drill bit, it’s best to use that to make the #8 x 1” screws set flat into the board.  Be very careful when you tighten these in – if you have inexpensive lumber with a particleboard core, and you use too much pressure (for example, if you drive them in with a drill), you’ll crush the cleat and break it in half.  It’s best to hand tighten these screws.

StandingDesk_4_Cleats1

Once you have the cleats in place, drive one or more screws from the cleats into the back board to hold it in place.  By putting them in here, you hide all of the screws so your finished surfaces are nice and clean.

StandingDesk_5_Cleats2

When you are done, you should have a nice looking table with no visible screws in the top, and only two small visible screws on each side.

StandingDesk_6_Desk

Here’s the final standing configuration on my desk:

StandingDesk_8_Standing

I used a bit of black electrical tape to tape the monitor power and video cords together so that when I move them they don’t get tangled.  It takes only a minute to switch between the two setups.  I don’t always make it all day standing – part of that depends on what else I have going on.  If I’ve had a hard workout in the morning, or if I’m playing racquetball later in the day, I’ll spend more time sitting.  Other days I’ll spend most of the day standing.  Either way, I’ve got the flexibility to choose.

One last thing – it does tend to get a bit uncomfortable standing on your feet for long periods, so I would recommend buying a 24” x 36” Sublime Gel Mat ($42-59 from Amazon).  There are cheaper ones available, but this one is highly rated and reviewed.  We used this in on our kitchen and it’s a really good one that should last you a long time.

StandingDesk_9_GelMat

I hope this post helps you out if you’re thinking of doing this.  Give it a try – if you use the copy paper box method, you’ve got nothing to lose other than a few minutes of your time.  If you find out you like it, then you can pursue more permanent solutions.

Posted by: lluppes | February 1, 2013

SyncFusion Metro Studio – Bargain Priced (for now!)

As I’ve been doing WinRT development the last month or so, I have found a couple of bargains out there.  SyncFusion has released a preliminary version of their WinRT toolkits at a bargain prices – the Essential Studio for WinRT for only $99!  The price will rise later this year as the toolkit matures, so you are strongly advised to take advantage of this price while it lasts.  It’s got some good tools right now that will continue to get better through the year.

One nugget in this toolkit that I’ve used quite a bit as I’ve been developing WinRT apps is the Metro Studio icon builder.  It has a nice collection of royalty-free icons that you can use in your applications (not just Windows Store apps!), but what I really like is how I can use them in my WinRT C#/XAML applications.  Unlike many icon collections, this one comes with a nice customizable editor:

MetroStudio

You pick a category select an icon, and you can customize it by turning it or changing the colors, etc. – all the usual stuff you would expect in an icon editor. But here’s the cool part for Windows 8 C#/XML developers:  you can export this icon definition as a XAML path.  Why is that important?  I’ll show you.

Click on the XAML button, and you should see the following:

XAMLPath

There’s a lot of extra stuff in there that you don’t really need — all you really need is the second Data attribute, which I highlighted.

In order to use this in your project, you need a button definition that can utilize a XAML path.  In your C#/XAML Windows Store app, go find the file StandardStyles.xaml, which is typically located in the Common folder.  There are a lot of Standard AppBarButton styles in there waiting for you to uncomment them which are very helpful, but you will need to add in this new button style code:

<Style x:Key="PathBasedAppBarButtonStyle" BasedOn="{StaticResource AppBarButtonStyle}" TargetType="Button">
  <Setter Property="ContentTemplate">
    <Setter.Value>
      <DataTemplate>
        <Path Width="20" Height="20" Stretch="Uniform" Fill="{Binding Path=Foreground, RelativeSource={RelativeSource Mode=TemplatedParent}}" Data="{Binding Path=Content, RelativeSource={RelativeSource Mode=TemplatedParent}}"/>
      </DataTemplate>
    </Setter.Value>
  </Setter>
</Style>

Now go into your XAML page where you actually want to use a button, and add a new button like this:

<Button Style="{StaticResource PathBasedAppBarButtonStyle}"
Content="[PATH DATA GOES HERE]" />

Paste the “M0,44.993L64…” code from up above into the Content attribute, like this:

<Button Style="{StaticResource PathBasedAppBarButtonStyle}"
Content="M0,44.993L64,44.993 64,51.735001 0,51.735001z M18.628,37.962999L45.372002,37.962999 45.372002,42.269 18.628,42.269z M4.4440002,3.855999L4.4440002,34.444999 59.556004,34.444999 59.556004,3.855999z M0.41899967,0L63.581001,0 63.581001,37.666 0.41899967,37.666z" />

That’s it!  When you run your app, you’ll have a customized icon that fits your app perfectly.  No image files to include, just a nice simple path string.  You can tweak the icon in the editor, then just update in the Path Data and you are all set.   Keeps things small and fast – pretty sweet!

Download your free trial version now at http://www.syncfusion.com/downloads/metrostudio and give it a try!

Posted by: lluppes | January 15, 2013

My First Windows Store App!

Well, the holidays are over, and it’s time to do some documentation.  Last November, I bought myself a Microsoft Surface and set about learning how to write programs for WinRT, and blogged about “Do I take the red pill or the blue pill?“, as I struggled with whether to use HTML/Javascript or C#/XAML, and learning about all of the new and/or missing features of WinRT.  I tried both the red and the blue pills, and I think both of them left my stomach unsettled.

Don’t get me wrong – I really like the new style of the “formerly known as Metro” apps in Windows 8.  I feel like I’ve had a big change in my design style, making it cleaner and lighter as Win8 Store Apps should be.  But along the way, I’ve had my share of frustrations as I’ve tried to do things that were simple in other environments but just plain didn’t work in WinRT apps.  And that’s another thing – just what do you call them?  Metro?  No.  WinRT apps? Windows Store Apps?  Windows 8 Apps?  Maybe…  Windows 8 still confuses me sometimes, even though I’m using it every day on a desktop, laptop, and Surface, and writing apps for it.  But I digress…

TimeCrunch

After many hours of work, I released my first app into the store in early January.  TimeCrunch is a time tracking app that dates back many years for me.  I’ve been using a version of this since back when I wrote it in 1997 using Microsoft Access.  It morphed into a classic ASP app as I learned that platform, and now is available for anyone to use as a free Windows Store App, and it may yet morph one more time.  The free edition stores the data locally using a SQLite database (which I’ll blog about more in the near future).  I’m working on another version that will run as an Azure based web application, plus an API that can be called from a Windows Store App, so you can share your data across multiple devices.  I wish I had more time to devote to this, but haven’t found the time yet for it.  Stay tuned to this blog for future announcements of it as that develops.

Posted by: lluppes | November 5, 2012

Mobile Internet Usage on the Rise

Interesting new stats onNetMarketShare this week:  Mobile browsers now account for more than 10% of ALL internet traffic, with Apple devices accounting for almost 60% of that traffic.

In other news, Internet Explorer still dominates on the desktop, but the phrase “Just Bing It” hasn’t caught on yet as Bing continues to trail Google and appeals to less than 5% of  users…

From http://www.netmarketshare.com/

Written by .

Posted by: lluppes | November 3, 2012

Coincidence…? I think not!

In my book “Delivering Mobile-Friendly Websites with MVC4“, I show how you can create a custom theme for your mobile website using jQuery.Mobile ThemeRoller, and in Chapter 6 I specifically show how you could create a theme that resembles that most famous of themes from Windows 3.1 – HotDog Stand.

I’ve been inspired by Scott Hanselmann’s blogs and presentations, so when I met him earlier this year at “That Conference“, I talked to him for a while and gave him a copy of my book as a thank you for inspiring me.

Today at the Microsoft Build Conference, Scott Hanselmann and John Galloway were presenting on ASP.NET (fast forward to 42:00), and I have to say I got a little surprise that brought a smile to my face.  During that presentation, Scott showed how to use the jQuery Mobile ThemeRoller and did it by creating…  the HotDog Stand theme!!!

Coincidence?  I think not! 

Not that I’m complaining or anything – after all, imitation is the highest form of flattery.

Scott – you’re welcome!  Feel free to use my examples any time!

Written by .

Posted by: lluppes | October 25, 2012

Do I take the red pill or the blue pill?

I know why you’re here. I know what you’ve been doing… why you hardly sleep, why you live alone, and why night after night, you sit by your computer. You’re looking for it. I know because I was once looking for the same thing. And when I thought I found it, it wasn’t really what I was looking for. I was looking for an answer. It’s the question that drives us. It’s the question that brought you here. You know the question, just as I did.

Yes, just how the heck do I write a functional WinRT app?

The answer is out there, and it’s looking for you, and it will find you if you want it bad enough. Maybe.

I’ve been on a quest recently, and I distinctly feel like Neo from the Matrix (one of my all-time favorite movies!).   Do I take the red pill or the blue pill?  I’ve been writing web sites for years, so I thought I would take the red pill and open up Visual Studio and be able to whip out a new WinRT app with HTML and JavaScript in no time.  I started with a simple app concept that I wanted to try, one that would have taken me a day or two in MVC4.  Chasing that dream down the rabbit hole has cost me many hours and sleepless nights.  Yes, it is pretty simple to get a sample app up and running that goes out and looks at Twitter feeds and displays them on your screen.  But I want a fully functional app that stores data locally, works offline, and occasionally syncs back up to an online database.  Should that be so difficult…?

What surprised me the most is that it seems like most of these tools right now for writing WinRT apps are just not quite there yet.  I was expecting the tooling to be a bit more mature, and it doesn’t look to me like it is.  We have a lot of simple samples, and a lot of blog posts from the last year that refer to things from the beta and pre-release stage that are just not quite right. Many of them that don’t even compile with the latest releases.  After many fruitless hours, I decided to abandon the HTML/JavaScript method and take the blue pill and start down the path of C#/XAML.  After a few days of working with that, it seems like it’s a little bit closer to what I was expecting for writing a WinRT app, but it’s still not wonderful.

I’ve been able to get a functioning application going that looks … “OK” …, but still with no love on the local storage front.  I found that you can use SQLite components (but only on x86, not ARM, unless you want to spend the time to migrate all the code yourself!) and I have wasted many hours looking at that.  It’s one of those things that looks great from a distance, but when you start to actually use it, you find out things like the sqlite-net package doesn’t support joining two tables (really?!!!).  I understand that it’s an open source project that needs some contributions, but right now I’m just trying to learn WinRT.  If I take yet another side trip to contribute writing the code to do joins for LINQ, that will just make me another month later to get my project running.  I was expecting these tools to be there.  Is it any wonder that there’s not a lot of apps in the Windows App Store yet?


On a related note, I’m excited to get my hands on my new Surface that’s supposed to arrive on Friday.  I’m not sure exactly where this is headed, but I’m afraid Windows 8/WinRT/Surface is going to be a bumpy ride for Microsoft.  I’ve been trying to wrap my head around this and figure out how I explain it to my customers and non-technical friends and family.  I don’t have any good answers yet that produce anything but blank stares and questioning looks.

So far, when I’m explaining Windows 8 and Surface, I feel like I’m making an awkward social introduction:

Hey – let me introduce you to Windows 8.  He’s Windows 7’s bi-polar schizophrenic cousin that’s having an identity crisis.  (Just don’t call him Metro – he gets really update if you use that nickname!) 

I’m not sure exactly what you should call it, … or how you will use it, …  or why the Start menu is gone, or lots of other things.  

Why yes, this tablet does run Windows.  

Umm… no, you can’t run  Windows applications on this Windows tablet because it’s an ARM-based Windows tablet (duh! isn’t that obvious?)  

But – I’m sure you’ll love him – isn’t he awesome?… 

hey – where are you going?  Come back here!

Sorry if this post is a bit of a rant, but I’m more than a little frustrated with WinRT right now.  There’s not a lot of good clean information on this topic, and I’m beginning to think my next book should be about how to do this, because I can’t seem to find this information anywhere.  Unfortunately, I have a long ways to go to get to that point before I feel like I know enough to write even a good blog post about this!  I’ll keep you posted as things evolve.

Written by .

Posted by: lluppes | October 14, 2012

Creating an Azure WebAPI for your Mobile Projects

This walkthrough will guide you through the steps necessary to create an Azure WebAPI project. There are several key components that are necessary for a successful Azure deployment if you want to make your project highly responsive, scalable, and affordable. The key pieces I will demonstrate here will be the use of Queues, Table Storage, and Worker Roles effectively.  There’s a lot to it, but once you have this down, it can make for some really nice back-end code.

The first step is to set up your Azure Account. You can register for a free 30-day trial account at http://windows.azure.com. Once you’ve set up the account, then go ahead and create a Storage account. You must come up with a unique name for your account. If you try to use one that already exists, you’ll get an error.
Bad:

Good:

Once you get it set up, you’ll want to record your name and find your storage keys for later use. Click on the Manage Keys link at the bottom of the screen and then copy that name and primary access key off for use later.

Once you have your Azure account all set up and ready, it’s time to open up Visual Studio 2012 and create a new cloud project. The first time you do this, you won’t be able to create any projects – you have to go load the Azure SDK first. The option for Cloud projects is there but just gives you a link to the SDK. Go ahead and load that and then restart Visual Studio.

One thing I don’t like about working with Azure projects is that you have to remember to start Visual Studio using the “Run as Administrator” option because the Azure Emulator requires it.

Now that you have the Azure SDK installed and you’ve started VS2012 in admin mode, it’s time to create your first project. If you have .NET 4.5 select at the top of the new project page you won’t have any available options. Currently you can only create .NET 4.0 projects (but .NET 4.5 support has been announced and is on the way very soon!). Make sure you have .NET Framework 4 select at the top of the page, then go ahead and select the Windows Azure Cloud Service project type and click OK (the real choices come on the next screen).

This is where you select the Options you want to use for your project. For this example, I’m going to create a Web site with some admin web pages and an API page for posting and returning data, and I also want a worker role to do background processing.

Since I selected an MVC4 Web Role, I’ll have to pick which type of MVC4 project I want – I chose Internet Application because I want a dual purpose website and API site.

We need to hook up our table storage account we created to this new Azure project, so we’ll add some configuration entries for that. Right click on the WebRole in the Roles section of your Azure project and click Properties, then select the Settings tab. Add the DataConnectionString and DiagnosticsConnectString to the All Configuration Settings tab, defaulting both to the UseDevelopmentStorage=true. On the Settings tab of your roles, switch to the Cloud configuration settings and change that to point to your real Azure storage account (not the Development storage). Get your Azure storage account name and primary access key you found previously when you set up your storage account.

Once you complete these for the WebRole, do the same thing with the Worker Role and add both settings to that project.

Because I have a web role and a worker role, and both of them will be processing data from the same storage location, I want to create a DataLayer Project that will handle all of the data interactions, so I’m going to create a plain old class library named DataLayer1. Once that’s created, I’ll add the NuGet packages of EntityFramework and Newtonsoft.Json, and then add references to Microsoft.WindowsAzure.ServiceRuntime, Microsoft.WindowsAzure.Configuration, Microsoft.WindowsAzure.StorageClient, Microsoft.WindowsAzure.Diagnostics, and System.Data.Services.Client.

After it’s compiled, then add a reference to your data layer project into in your WebRole and WorkerRole projects.

Let’s get back to our DataLayer project.  Rename Class1.cs to TimeRepository.cs and add the following placeholder code (which will get fleshed out later):

using Microsoft.WindowsAzure.StorageClient;

namespace LuppesTime
{
  public interface ITimeRepository
  {
    CloudQueueMessage GetMessage();
    bool ProcessQueueEntry(string partitionKey, string rowKey);
    void DeleteMessage(CloudQueueMessage msg);
  }
  public class TimeRepository : ITimeRepository
  {
    public CloudQueueMessage GetMessage()
    {
      //TODO: Implement this method later
      return null;
    }
    public bool ProcessQueueEntry(string partitionKey, string rowKey)
    {
      //TODO: Implement this method later
      return false;
    }
    public void DeleteMessage(CloudQueueMessage msg)
    {
      //TODO: Implement this method later
    }
  }
}

One of the odd things of working with Azure is the occasional errors that you get when trying to connect to the database or storage accounts, which are referred to as Transient Faults. You need to code for this in your application, but fortunately, there is a pretty easy way to handle that problem. For now, search for and install the NuGet Package “Transient Fault Handling Application Block” and apply it to your Datalayer, WebRole, and WorkerRole, and we’ll see where that comes into play soon.

Now it’s time to configure the WorkerRole with Azure goodness. To do that, we’ll replace the generic OnStart function with the following code to set up your environment:

private ITimeRepository db;
public override bool OnStart()
{
 // instantiate our DataLayer
 db = new TimeRepository();

 // read storage account configuration settings
 CloudStorageAccount.SetConfigurationSettingPublisher((configName, configSetter) =>
 {
 configSetter(RoleEnvironment.GetConfigurationSettingValue(configName));
 });
 var storageAccount = CloudStorageAccount.FromConfigurationSetting("DataConnectionString");

 // Set the maximum number of concurrent connections
 ServicePointManager.DefaultConnectionLimit = 12;

 // For information on handling configuration changes
 // see the MSDN topic at http://go.microsoft.com/fwlink/?LinkId=166357.

 DiagnosticMonitorConfiguration diagConfig = DiagnosticMonitor.GetDefaultInitialConfiguration();

 //Enable Scheduled Transfer
 diagConfig.Logs.ScheduledTransferPeriod = TimeSpan.FromSeconds(30);
 diagConfig.PerformanceCounters.ScheduledTransferPeriod = TimeSpan.FromMinutes(5.0);
 diagConfig.Directories.ScheduledTransferPeriod = TimeSpan.FromHours(1);

 //// OPTIONAL - add Performance Counter Monitoring
 //PerformanceCounterConfiguration procTimeConfig = new PerformanceCounterConfiguration();
 //// FYI - run typeperf.exe /q to query to see counter names
 //procTimeConfig.CounterSpecifier = @"\Processor(*)\% Processor Time";
 //procTimeConfig.SampleRate = System.TimeSpan.FromSeconds(10);
 //diagConfig.PerformanceCounters.DataSources.Add(procTimeConfig);

 // add Event Collection from Windows Event Log
 // http://msdn.microsoft.com/en-us/library/dd996910(VS.85).aspx
 diagConfig.WindowsEventLog.DataSources.Add("System!*");
 diagConfig.WindowsEventLog.DataSources.Add("Application!*");

 try
 {
 DiagnosticMonitor.Start("DiagnosticsConnectString", diagConfig);
 Trace.TraceInformation(string.Format("{0}", "WorkerRole OnStart completed"));
 }
 catch (Exception ex)
 {
 Trace.TraceInformation(string.Format("{0}", "Error Starting Diagnostics! " + ex.Message));
 }

 // Capture full crash dumps (FYI - ASP.net will trap some of these crashes and you might not see them)
 CrashDumps.EnableCollection(true);

 return base.OnStart();
}

Since this is a worker role, we’re going to want this worker to go out and search the Queue for things to process. Let’s replace the Run function with this code in order to set up your worker process to go get queue entries. In the previous code, we set up a link to the db = ITimeRepository (which is a reference to our Data Layer code), so we’ll call functions in that library to get and process Queue entries. This code just hangs around looking for new Queue entries. You can change the Sleep interval to whatever value you want. I’ve set it to 15 seconds here so you have a little delay in case you want to look at the records before they are processed.

public override void Run()
{
  Trace.TraceInformation("Worker: Listening for queue messages...");
  while (true)
  {
    try
    {
      // retrieve a new message from the queue
      CloudQueueMessage msg = db.GetMessage();
      if (msg != null)
      {
        // parse message retrieved from queue
        var messageParts = msg.AsString.Split(new char[] { ',' });
        var partitionKey = messageParts[0];
        var rowkey = messageParts[1];
        Trace.TraceInformation("Worker: Found queue entry - '{0}-{1}'.", partitionKey, rowkey);
        db.ProcessQueueEntry(partitionKey, rowkey);
        db.DeleteMessage(msg);
        Trace.TraceInformation("Worker: Finished Queue processing - '{0}-{1}'.", partitionKey, rowkey);
      }
      else
      {
        // sleep time is in milliseconds – this is set to 15 seconds so you have
        // time to look at the queue before it gets processed
        System.Threading.Thread.Sleep(15000);
      }
    }
    catch (StorageClientException ex)
    {
      Trace.TraceError("Worker: Exception when processing queue item. Message: '{0}'", ex.Message);
      System.Threading.Thread.Sleep(5000);
    }
  }
}

Now it’s time to configure the WebRole with the same Azure goodness. Replace the OnStart function with the following code to set up your environment:

public override bool OnStart()
{
  // For information on handling configuration changes
  // see the MSDN topic at http://go.microsoft.com/fwlink/?LinkId=166357.

  DiagnosticMonitorConfiguration diagConfig = DiagnosticMonitor.GetDefaultInitialConfiguration();

  //Enable Scheduled Transfer
  diagConfig.Logs.ScheduledTransferPeriod = TimeSpan.FromSeconds(30);
  diagConfig.PerformanceCounters.ScheduledTransferPeriod = TimeSpan.FromMinutes(5.0);
  diagConfig.Directories.ScheduledTransferPeriod = TimeSpan.FromHours(1);

  //// add Performance Counter Monitoring
  //PerformanceCounterConfiguration procTimeConfig = new PerformanceCounterConfiguration();
  //// FYI - run typeperf.exe /q to query to see  counter names
  //procTimeConfig.CounterSpecifier = @"\Processor(*)\% Processor Time";
  //procTimeConfig.SampleRate = System.TimeSpan.FromSeconds(10);
  //diagConfig.PerformanceCounters.DataSources.Add(procTimeConfig);

  // add Event Collection from Windows Event Log
  // Syntax: !
  // http://msdn.microsoft.com/en-us/library/dd996910(VS.85).aspx
  diagConfig.WindowsEventLog.DataSources.Add("System!*");
  diagConfig.WindowsEventLog.DataSources.Add("Application!*");

  try
  {
    DiagnosticMonitor.Start("DiagnosticsConnectString", diagConfig);
    System.Diagnostics.Trace.TraceInformation(string.Format("{0}", "WorkerRole OnStart completed"));
  }
  catch (Exception ex)
  {
    //WriteToLog(string.Format("{0}", "Error Starting Diagnostics! " + ex.Message));
    System.Diagnostics.Trace.TraceInformation(string.Format("{0}", "Error Starting Diagnostics! " + ex.Message));
  }

  // Capture full crash dumps  (FYI - ASP.net will trap some of these crashes and you might not see them)
  CrashDumps.EnableCollection(true);
  return base.OnStart();
}

In a previous section, we added the Transient Fault Tolerance block. In order for that to work right, we need add in the RetryPolicy Code and the TypeRegistrationProviders code to the Web.Config in the WebRole and the app.config in the WorkerRole.

<configuration>
  <configSections>
    <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=4.4.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
    <section name="typeRegistrationProvidersConfiguration" type="Microsoft.Practices.EnterpriseLibrary.Common.Configuration.TypeRegistrationProvidersConfigurationSection, Microsoft.Practices.EnterpriseLibrary.Common, Version=5.0.505.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
    <section name="RetryPolicyConfiguration" type="Microsoft.Practices.EnterpriseLibrary.WindowsAzure.TransientFaultHandling.Configuration.RetryPolicyConfigurationSettings, Microsoft.Practices.EnterpriseLibrary.WindowsAzure.TransientFaultHandling" />
  </configSections>
  <RetryPolicyConfiguration defaultRetryStrategy="Fixed Interval Retry Strategy" defaultAzureStorageRetryStrategy="Fixed Interval Retry Strategy" defaultSqlCommandRetryStrategy="Backoff Retry Strategy">
    <incremental name="Incremental Retry Strategy" retryIncrement="00:00:01" initialInterval="00:00:01" maxRetryCount="10" />
    <fixedInterval name="Fixed Interval Retry Strategy" retryInterval="00:00:05" maxRetryCount="6" firstFastRetry="true" />
    <exponentialBackoff name="Backoff Retry Strategy" minBackoff="00:00:05" maxBackoff="00:00:45" deltaBackoff="00:00:04" maxRetryCount="10" />
  </RetryPolicyConfiguration>
  <typeRegistrationProvidersConfiguration>
    <clear />
    <add sectionName="RetryPolicyConfiguration" name="RetryPolicyConfiguration" />
  </typeRegistrationProvidersConfiguration>
</configuration>

In order to get access to our Azure table storage account in our web application, we need to configure that in the startup. To keep the Global.asax.cs clean, we’ll create a new AzureConfig.cs file in the App_Start folder of our WebRole project, and then add a call in our Application_Start event in the Global.asax.cs file.

// in Global.asax.cs
protected void Application_Start()
{
  AzureConfig.RegisterAzureSettings();
}

 

//[contents of App_Start\AzureConfig.cs file]
using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.ServiceRuntime;

namespace LuppesTime
{
 public static class AzureConfig
 {
 public static void RegisterAzureSettings()
 {
 CloudStorageAccount.SetConfigurationSettingPublisher((configName, configSetter) =>
 {
 configSetter(RoleEnvironment.GetConfigurationSettingValue(configName));
 });
 }
 }
}

We’ve finished most of the Azure plumbing code and it’s time to start creating some real application code. Go back into the DataLayer project and let’s create some code there. First we’ll create a class that defines what the record looks like that we’re going to store in the TableStorage table. Create a file named TimeTableStorage.cs and put this code in it.

using System;
using Microsoft.WindowsAzure.StorageClient;

namespace LuppesTime
{
  public class TimeTableStorage : TableServiceEntity
  {
    public TimeTableStorage()
    {
      CreateDateTime = DateTime.UtcNow;
      ProcessedInd = "N";
      PartitionKey = DateTime.UtcNow.ToString("MMddyyyy");
      // Row key allows sorting, so we make sure the rows come back in time order.
      RowKey = string.Format("{0:10}_{1}", DateTime.MaxValue.Ticks - DateTime.Now.Ticks, Guid.NewGuid());
    }
    public string XMLData { get; set; }
    public string ProcessedInd { get; set; }
    public DateTime CreateDateTime { get; set; }
    public DateTime? ProcessedDateTime { get; set; }
    public string StatusMessage { get; set; }
  }
}

Next we’ll have to create a Storage Context class which defines this table to the Azure Table Service.

using System.Linq;
using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.StorageClient;

namespace LuppesTime
{
  public class TimeTableStorageContext : TableServiceContext
  {
    public TimeTableStorageContext(string baseAddress, StorageCredentials credentials)
      : base(baseAddress, credentials)
    {
    }
    public IQueryable TimeTable
    {
      get
      {
        return this.CreateQuery("TimeTable");
      }
    }
  }
}

Now that we have our table structure and data context set up, now we can start to use it. Edit your TimeRepository.cs file and put this code in it. This class initialization code sets up all of the table storage and queue plumbing that we’ll need to make everything work.

using System;
using System.Diagnostics;
using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;
using Microsoft.Practices.EnterpriseLibrary.WindowsAzure.TransientFaultHandling;
using Microsoft.Practices.EnterpriseLibrary.WindowsAzure.TransientFaultHandling.AzureStorage;
using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.StorageClient;

#region Initialization
private TimeTableStorageContext context;
private static CloudStorageAccount storageAccount;
private static CloudBlobClient blobStorage = null;
private static CloudQueueClient queueStorage = null;
private static CloudQueue queue;
private static CloudBlobContainer container;

///
/// static constructor initializes the storage account and
/// creates the tables if they don't already exist.
/// static method makes sure that this is only called once
///
static TimeRepository()
{
  storageAccount = CloudStorageAccount.FromConfigurationSetting("DataConnectionString");
  CloudTableClient.CreateTablesFromModel(
      typeof(TimeTableStorageContext),
      storageAccount.TableEndpoint.AbsoluteUri,
      storageAccount.Credentials);

  // initialize blob storage
  blobStorage = storageAccount.CreateCloudBlobClient();
  // warning: this name CANNOT contain capital letters!
  container = blobStorage.GetContainerReference("timeblobs");

  // initialize queue storage
  queueStorage = storageAccount.CreateCloudQueueClient();
  // warning: this name CANNOT contain capital letters!
  queue = queueStorage.GetQueueReference("timequeue");

  Trace.TraceInformation("Creating container and queue...");

  bool storageInitialized = false;
  while (!storageInitialized)
  {
    try
    {
      // create the blob container and allow public access
      container.CreateIfNotExist();
      var permissions = container.GetPermissions();
      permissions.PublicAccess = BlobContainerPublicAccessType.Container;
      container.SetPermissions(permissions);

      // create the message queue(s)
      queue.CreateIfNotExist();

      storageInitialized = true;
    }
    catch (StorageClientException e)
    {
      if (e.ErrorCode == StorageErrorCode.TransportError)
      {
        Trace.TraceError("Storage services initialization failure. "
          + "Check your storage account configuration settings. If running locally, "
          + "ensure that the Development Storage service is running. Message: '{0}'", e.Message);
        System.Threading.Thread.Sleep(5000);
      }
      else
      {
        throw;
      }
    }
  }
}
///
/// constructor sets up the retry policy and queue context
///
public TimeRepository()
{
  this.context = new TimeTableStorageContext(storageAccount.TableEndpoint.AbsoluteUri, storageAccount.Credentials);
  this.context.RetryPolicy = RetryPolicies.Retry(3, TimeSpan.FromSeconds(1));
}
#endregion

#region Transient Fault Tolerance Hooks
// --> to enable TFT, simply wrap your calls inside the retryPolicy.ExecuteAction call, like this:
// BEFORE:
//    return
//      (from p in db.Note select p);
// AFTER:
//    return this.retryPolicy.ExecuteAction( () =>
//      (from p in db.Note select p)
//    );
private RetryManager _RetryManager;
private Microsoft.Practices.TransientFaultHandling.RetryPolicy _RetryPolicy;
public Microsoft.Practices.TransientFaultHandling.RetryPolicy retryPolicy
{
  get
  {
    if (_RetryPolicy == null)
    {
      _RetryManager = EnterpriseLibraryContainer.Current.GetInstance();
      _RetryPolicy = _RetryManager.GetRetryPolicy("Incremental Retry Strategy");
    }
    return _RetryPolicy;
  }
}
#endregion

Now that we have all the plumbing set up, let’s create a function called AddTableAndQueueEntry method in your TimeRepository that will create a new TableStorage record and then add a queue entry for the WorkerRole telling where to find the next bit of work it should do.

public interface ITimeRepository
{
  bool AddTableAndQueueEntry(TimeTableStorage newItem);
}
public bool AddTableAndQueueEntry(TimeTableStorage newItem)
{
  try
  {
    if (newItem != null)
    {
      retryPolicy.ExecuteAction(() =>
      {
        this.context.AddObject("time", newItem);
        this.context.SaveChanges();
      });

      if (queueStorage != null)
      {
        // queue a message to process the image
        var queue = queueStorage.GetQueueReference("timequeue");
        var message = new CloudQueueMessage(String.Format("{0},{1}", newItem.PartitionKey, newItem.RowKey));
        retryPolicy.ExecuteAction(() =>
        {
          queue.AddMessage(message);
        });
        System.Diagnostics.Trace.TraceInformation("New Queue Entry: Process post '{0},{1}'", newItem.PartitionKey, newItem.RowKey);
      }

      return true;
    }
    else
    {
      return false;
    }
  }
  catch (Exception ex)
  {
    Trace.TraceError(string.Format("Error posting entry! {0} {1}", GetExceptionMessage(ex), SerializeObjectToJson(newItem)));
    return false;
  }
}

Now that we have our data repository set up, let’s go back to the WebRole and create an API method so that we can call it and create a new item. Create an API folder in the WebRole project, and add a Test.cs file to that folder as a new Controller.

Put the following code in the TestController. This code is pretty simplistic and doesn’t really reflect the reality of how you would create a web service API, but it works for this example. If we just hit the “/api/test” URL in the browser, it will give us a message telling us to supply a parameter so we can see it’s working. If we supply a parameter (i.e. /api/test/666), it will go into the other method and call the datalayer AddTableAndQueueEntry method with that parameter.

using System;
using System.Diagnostics;
using System.Net;
using System.Net.Http;
using System.Web.Http;

namespace LuppesTime.API
{
  public class TestController : ApiController
  {
    public ITimeRepository db = new TimeRepository();
    // GET api/test
    public string Get()
    {
      return "Call this with a parameter to create a queue entry!";
    }
    // GET api/test/5
    public HttpResponseMessage Get(int id)
    {
      TimeTableStorage post = new TimeTableStorage();
      try
      {
        post.XMLData = string.Format("{0}", id);
        if (db.AddTableAndQueueEntry(post))
        {
          Trace.TraceInformation(string.Format("Posted data from Id {0} Bytes {1}", post.XMLData, post.XMLData.Length));
          return Request.CreateResponse(HttpStatusCode.OK, "Data Accepted!");
        }
        else
        {
          Trace.TraceWarning(string.Format("Error while posting data {0}", post.XMLData));
          return Request.CreateResponse(HttpStatusCode.BadRequest, "Data Rejected!");
        }
      }
      catch (Exception ex)
      {
        Trace.TraceError(string.Format("Error while processing data {0} {1}", post.XMLData, ex.Message));
        return Request.CreateResponse(HttpStatusCode.BadRequest, "Error! " + ex.Message);
      }
    }
  }
}

Let’s return to the DataLayer project and update the functions we stubbed out earlier. The first two are pretty simple – to work with the queue we just do a Get or Delete call.

public CloudQueueMessage GetMessage()
{
  return queue.GetMessage();
}
public void DeleteMessage(CloudQueueMessage msg)
{
  queue.DeleteMessage(msg);
}

The ProcessQueueEntry is a little more complicated. We have to go fetch the table storage record, process it, then update it and remove it from the queue so we don’t process it again.

public bool ProcessQueueEntry(string partitionKey, string rowKey)
{
  TimeTableStorage entry = null;
  try
  {
    IEnumerable results = null;
    retryPolicy.ExecuteAction(() =>
    {
      results =
        from g in this.context.TimeTable
        where g.PartitionKey == partitionKey && g.RowKey == rowKey
        select g;
    });
    entry = results.FirstOrDefault();

    //TODO: write a process that will take the XML from table storage and process it, returning a batch number for cross reference
    int BatchId = 1;

    if (BatchId > 0)
    {
      Trace.TraceInformation(string.Format("Successfully Processed Queue Entry {0} {1} {2}", entry.XMLData, entry.PartitionKey, entry.RowKey));
      entry.ProcessedInd = "Y";
      entry.BatchId = BatchId;
      entry.StatusMessage = "Processed";
    }
    else
    {
      Trace.TraceError(string.Format("Failure Processing Queue Entry {0} {1} {2}", entry.XMLData, entry.PartitionKey, entry.RowKey));
      entry.ProcessedInd = "F";
      entry.BatchId = 0;
      entry.StatusMessage = "Processing failed!";
    }

    entry.ProcessedDateTime = DateTime.UtcNow;
    this.context.UpdateObject(entry);
    this.context.SaveChanges();
    return true;
  }
  catch (Exception ex)
  {
    Trace.TraceError(string.Format("Error processing queue entry: {0} {1} {2} {3}", GetExceptionMessage(ex), entry.XMLData, entry.PartitionKey, entry.RowKey));
    return false;
  }
}

We’re done with coding, now it’s time to test. Fire up your project and you should be able to test it out by using the Azure Emulator that’s built into Visual Studio once you install the Azure SDK.

Deploying to Azure

Once you are satisfied that your project is working on your local test environment, it’s time to deploy to Azure.  To deploy to Azure, right-click on the Azure project and select Publish, which will be pretty blank the first time.

When the Azure popup comes up blank, click on the Sign In link to go get your publishing credentials. Your browser will open up and prompt you to sign in to Azure and then will automatically download your credentials. Save it somewhere it your project folder, then return to the Azure popup and click on the Import button and then import your downloaded credentials, and you should see your Azure account info in the subscription dropdown, then click Next.

If you haven’t created any hosted services (and if you’ve been following along, you haven’t done that yet…), then give your new service a name here, otherwise just select one from the list.

Since we’re using Table Storage, we’ll have to flip over to the Advance Settings to enter that in the Storage Info.

Once you’ve done that, click Next, then click on Publish and sit back and wait – it could take 10 minutes or so for the deployment to finish. You should see your build output window pop up quickly, then an Azure deployment window.

While you are waiting, let’s go hook up our links to the table storage on the Azure server so we can see those tables. Open the Server Explorer and add a new storage account. You’ll need that same storage account name and key that you used way back in the beginning.

If you deploy as a Staging instance, you’ll get a url that looks like http://{guid}.cloudapp.net . If you deploy as a Production instance, you’ll be able to use your url that looks like http://yourappname.cloudapp.net.  Once it’s deployed, you should see a successful message.

Browse to your website at http://{guid}.cloudapp.net to verify it’s working by clicking the link now visible on the left hand side of the Azure Activity Log window. Browse to your API page at http://{guid}.cloudapp.net/api/Test to call the code you wrote that will create an entry in table storage and queue. You should get back an XML packet containing “Data Accepted!”

Go browse your Table Storage using the VS Server Explorer – you should have around 10-15 seconds to see it before the worker process picks it up and processes it. If you got there before the worker, the Processed flag should be set to “N”. If you want 15 seconds and refresh the view, you should see that Processed is set to “Y” now.

You can also check out the server logs by viewing the Tables\WADLogsTable – anything that you entered with the Trace statements should show up in these logs for you to view.

That’s it – you’ve now deployed a Windows Azure service that uses Table Storage, Queues, Worker Processes, Diagnostics Logging and all sorts of Azure goodness. You can scale this solution up to handle massive traffic volumes if your application takes off.

I’ve included a Sample Source Code Project here for your reference.  Enjoy!

Lyle

Written by .

Posted by: lluppes | September 30, 2012

Minnesota Developers Conference 2012 Presentation

I recently gave a presentation at the Minnesota Developers Conference on September 13th, and a friend of mine was on hand to record it.  The video is not the greatest quality (not Bill’s fault!) – I scaled it down to conserve space and had to split it into two parts so it would upload to Vimeo, but it’s still good enough to see the presentation.    All of the slides and source code are available for download at http://mdc.ilmservice.com/download.

Enjoy!

 

 

Written by .

Posted by: lluppes | September 29, 2012

Creating a ResponsAdaptive WebSite

a.k.a. How to Use Bootstrap and jQuery.Mobile with MVC4 

I’ve been hearing a lot of buzz about Bootstrap and wanted to experiment with it on my website, but I still wanted to keep the mobile look and feel that I currently had as I have documented in my book “Delivering Mobile-friendly Websites with MVC4“. My goal was to create a nice responsive site for the desktop while maintaining the jQuery.Mobile version for mobile devices, and I think I have succeeded in that. As part of that process, I created two NuGet packages that you can use to easily add these features to your own MVC4 sites.

Making it Responsive

To make things easier for future self (and for you!), I created a NuGet package with all of the pieces that you need for running Bootstrap in your MVC4 website. Create a new MVC4 project, then install the package LCI.Bootstrap.MVC4.  You could just install the Twitter.Bootstrap package, but that doesn’t give you an MVC Layout page, so this one does both with just one command.

PM> install-package LCI.Bootstrap.MVC4
Attempting to resolve dependency 'Twitter.Bootstrap (? 2.1.1)'.
Successfully installed 'Twitter.Bootstrap 2.1.1'.
Successfully installed 'LCI.Bootstrap.MVC4 1.0.0'.
Successfully added 'Twitter.Bootstrap 2.1.1' to MvcApplication1.
Successfully added 'LCI.Bootstrap.MVC4 1.0.0' to MvcApplication1.

This NuGet package will get Twitter.Bootstrap for you automatically, then create the Layout file that you need to make it work right with MVC4. It also adds a few images and a CSS file in the content folder, and a sample page with Tabs. It will automatically pop up a ReadMe file for the package walks you through the next few critical steps.

The NuGet package creates a Views\Shared\_Layout_Bootstrap.cshtml. By default, all of your pages reference the _Layout.cshtml file, so if you want your whole site to use the new layout, just rename (or delete) the existing _Layout.cshtml file and then rename the _Layout_Bootstrap.cshtml to _Layout.cshtml.

Since we are using MVC4, we need to take advantage of the new bundling feature, so I created some new bundles for the Bootstrap files. (These bundles are referenced in the _Layout file you just renamed in the previous step.)  Add the following code to your BundleConfig.cs file:  (I can’t add code to your existing files because I haven’t figured out how to make NuGet do that non-destructively yet…!)

public class BundleConfig
{
  // existing bundle code goes here...
  bundles.Add(new ScriptBundle("~/bundles/bootstrapjs").Include(
    "~/Scripts/bootstrap.js"));
  bundles.Add(new StyleBundle("~/Content/bootstrapcss").Include(
    "~/Content/bootstrap.css",
    "~/Content/SiteBootstrap.css"));
}

Bootstrap.css came with the Bootstrap package, and I added my own SiteBootstrap.css for changes and additions that I wanted to use to the styles. For example, if you want to change the color of the header, that’s defined in SiteBootstrap.css file and is simple to change.

The NuGet package also installs an example tabbed page that shows you how you can easily use features like tabs that are built into Bootstrap. I didn’t want to mess with your existing Home controller, so you will have to manually add the following lines to your HomeController.cs file:

public ActionResult Tabs()
{
  return View();
}

That’s it! Compile and run and you should see a site that looks something like this:

Bootstrap Example

Another nice sample that I’ve set up in this layout file is that it has a revolving carousel in the header so that you can have animated ads.  You can swap out “Page 1/Page 2/Page 3″ for whatever pages you want to use very easily.

The Tabs Example page shows how you can easily add tabbed content with just these few lines of code:

<ul id="myTab" class="nav nav-tabs">
  <li class="active">
    <a href="#Tab1" data-toggle="tab">About the Book</a>
  </li>
  <li>
    <a href="#Tab2" data-toggle="tab">More Info</a>
  </li>
</ul>
<div id="myTabContent" class="tab-content">
  <div class="tab-pane active" id="Tab1">
    <h2>About the Book!<h2>
    ... content here ...
  </div>
  <div class="tab-pane" id="Tab2">
    <h2>More Info</h2>
    ... content here ...
  </div>
</div>

That simple code produces a tabbed page that looks like this:

Bootstrap Tabs

Making it Adaptive

Once I had the responsive part of the project in place, I wanted to make it adaptive so it returned mobile views to mobile devices. To make this a bit simpler, I created another NuGet package called LCI.jQueryMobile.MVC4 that pulls in jQuery.Mobile and creates some default mobile Layout pages for you. The ReadMe file for the package walks you through a few critical steps.

I’m taking advantage of the DisplayModeProvider technology built into MVC4, so I’ve added a new configuration file (DisplayModeConfig.cs) in the App_Start folder. You’ll need to update the Global.asax.cs file to reference function that, adding the following line:

protected void Application_Start()
{
  // existing code goes here
  DisplayModeConfig.RegisterDisplayModes();
}

The code in the DisplayModeConfig.cs file creates new display modes by looking at the UserAgent that is passed in by the web browser, then deciding which DisplayMode should be used for the current request.  Here’s an excerpt from that file that shows how it does that:

DisplayModeProvider.Instance.Modes.Insert(0,
new DefaultDisplayMode("Phone")
{
  ContextCondition = (context => ((context.GetOverriddenUserAgent() != null) &&
    (
      (context.GetOverriddenUserAgent().IndexOf("iPhone",
        StringComparison.OrdinalIgnoreCase) >= 0) ||
      (context.GetOverriddenUserAgent().IndexOf("iPod",
        StringComparison.OrdinalIgnoreCase) >= 0) ||
      (context.GetOverriddenUserAgent().IndexOf("Droid",
        StringComparison.OrdinalIgnoreCase) >= 0) ||
      (context.GetOverriddenUserAgent().IndexOf("Blackberry",
        StringComparison.OrdinalIgnoreCase) >= 0) ||
      (context.GetOverriddenUserAgent().StartsWith("Blackberry",
        StringComparison.OrdinalIgnoreCase))
    )
  ))
});

(For more information on how that works, go watch my presentation online at http://blog.luppes.com/2012/09/30/mdc201/ or check out my book!)

Just like before, we want to take advantage of the new bundling feature, so I created some new bundles for jQuery.Mobile that you will need to add to the BundleConfig.cs file:

public class BundleConfig
{
  // existing bundle code goes here...
  bundles.Add(new ScriptBundle("~/bundles/MobileJS").Include(
    "~/Scripts/jquery.mobile-{version}.js",
    "~/Scripts/jquery-{version}.js"));
  bundles.Add(new StyleBundle("~/Content/MobileCSS").Include(
    "~/Content/jquery.mobile.structure-{version}.min.css",
    "~/Content/jquery.mobile-{version}.css"));
}

Now if you browse to this site with a tablet or phone, you’ll get a page that looks like this:

jQueryMobile Example

The Result: A ResponsAdaptive WebSite

Voila! Works like a champ! There are a lot of other topics we could get in to, like using partial views to avoid replicating content, but that’s a subject for another day.  You should be able to use these two NuGet package to create your own ReponsAdaptive website in no time!

Resources

If you want to download the project I created for this post, you can get it here.

MVC4 Bootstrap NuGet Package LCI.Bootstrap.MVC4

MVC4 jQuery.Mobile NuGet Package  LCI.jQueryMobile.MVC4

If you want to learn how to make your own NuGet packages, go check out Scott Hanselman’s excellent post.

Lyle

Written by .

Older Posts »

Categories

Follow

Get every new post delivered to your Inbox.