# Sunday, March 28, 2010

I've been wanting a simplified WCF plugin architecture for .NET Windows service with easy debug console mode to make my life easier. Building services with Windows Communication Foundation (WCF) is simple and hard. The service and data contract code is simple, like this:

namespace Test2Common	
{
  [ServiceContract]
  public interface IMyOtherService
  {
    [OperationContract, FaultContract(typeof(WcfServiceFault))]
    string GetName(string seed);

    [OperationContract, FaultContract(typeof(WcfServiceFault))]
    Person GetPerson(int id);
  }

  [DataContract]
  public class Person
  {
    [DataMember]
    public string Name { get; set; }

    [DataMember]
    public string Title { get; set; }
  }
}

But that is where simple ends. The hosting and client proxy code and the configuration XML (or code) is not simple. Even when I use tools to generate these artifacts, I find myself having to tweak and fix and delve deeper than time permits. And since I prefer simple, I decided to create a reusable framework for hosting my limited scope services. Here's what I wanted (download PluggableWcfServiceHost.zip (38.05 KB)):

  • Fast net.tcp binding
  • Windows credentials and authentication
  • Encrypted and signed transport (no packet sniffing allowed)
  • Simplified configuration (hide everything I don't want to see)
  • Windows Service host that behaves like a Console app when I'm debugging
  • Dynamic loading of the service (no changes to the host code to add a new service)
  • Generic client so I don't have to write or generate proxy code
  • Client that is truly IDisposable (hide Abort vs Close for me)
  • Long timeout in DEBUG mode so I can really take my time while debugging
  • Inclusion of exception details in DEBUG mode only
  • Base service class with a simple Authorize method to support multiple Windows groups
  • Support for multiple Windows group authorization
  • Identical configuration for server and client
  • Cached resolution of service plugin service and contract types
  • Minimal number of assemblies (projects) in the solution
  • Keep the implementation of the service hidden from the client
  • (Probably some I've forgotten to mention)

Here's the simplified config with two services configured:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="wcfServices" 
          type="WcfServiceCommon.WcfServiceConfigurationSection, WcfServiceCommon" />
  </configSections>
  <appSettings/>
  <connectionStrings/>
  <wcfServices consoleMode="On">
    <services>
      <add key="test1"
          serviceAddressPort="localhost:2981"
          endpointName="Test1EndPoint"
          authorizedGroups="WcfServiceClients,someOtherGoup"
          hostType="Test1Service.ThatOneService, Test1Service"
          contractType="Test1Common.IThatOneService, Test1Common" />
      <add key="test2"
          serviceAddressPort="localhost:2981"
          endpointName="Test2EndPoint"
          authorizedGroups="WcfServiceClients,someOtherGoup"
          hostType="Test2Service.MyOtherService, Test2Service"
          contractType="Test2Common.IMyOtherService, Test2Common" />
    </services>
  </wcfServices>
</configuration>

And here's the implementation of the service (It really is simple):

namespace Test2Service
{
  public class MyOtherService : WcfServiceBase, IMyOtherService
  {
    public string GetName(string seed)
    {
      base.Authorize();
      return "This is my name: " + seed.ToUpper();
    }

    public Person GetPerson(int id)
    {
      base.Authorize();
      return new Person { Name = "Donald Trumpet", Title = "King of the Hill" };
    }
  }
}

Now for the really fun part. The client. Hey, where's the proxy? Hidden away just like it ought to be.

namespace WcfSvcTest
{
  class Program
  {
    static void Main(string[] args)
    {
      using (var client1 = WcfServiceClient<IThatOneService>.Create("test1"))
      {
        Console.WriteLine(client1.Instance.GetName("seed"));
        var add = client1.Instance.GetAddress(8);
        Console.WriteLine("{0}", add.City);
      }

      using (var client2 = WcfServiceClient<IMyOtherService>.Create("test2"))
      {
        try
        {
          Console.WriteLine(client2.Instance.GetName("newseed"));
          var per = client2.Instance.GetPerson(7);
          Console.WriteLine("{0}, {1}", per.Name, per.Title);
        }
        catch (FaultException<WcfServiceFault> fault)
        {
          Console.WriteLine(fault.ToString());
        }
        catch (Exception e) //handles exceptions not in wcf communication
        {
          Console.WriteLine(e.ToString());
        }
      }

      Console.ReadLine();
    }
  }
}

To save space, I only wrapped the use of the client in try catch on the second test service.

Note: You have to remember that the WcfServiceHost requires the "common" and the "service" assemblies of your dynamically loaded services in it's bin folder. The client (see WcfSvcTest project in the solution) will also need a copy of the "common" assemblies in it's bin folder. You'll find I'm doing that for the test using post-build commands (copy $(TargetPath) $(SolutionDir)WcfServiceHost\bin\debug\). And of course, both need to have identical config sections as shown in the code.

I hope you find this WCF plugin architecture and the accompanying code useful. I will certainly be using it. If you do use it, please let me know how it goes.

Download PluggableWcfServiceHost.zip (38.05 KB)

posted on Sunday, March 28, 2010 8:58:40 PM (Mountain Daylight Time, UTC-06:00)  #    Comments [0]
# Thursday, March 25, 2010

Let’s face it. Most of us code slingers have no innate understanding of what makes a great user experience (UX) design. We spend so many hours in front of multiple user interfaces that navigating and using software becomes virtually intuitive, instinctual. But we are not “normal” users.

I’ve just finished reading and mean to re-read Whitney Hess’s “25 Guiding Principles for UX Designers” on Inside Tech. It’s a great piece with some very good references. I recommend you read the entire article multiple times. Here are some of my favorites (my number is not the same as Whitney’s):

1. Understand the underlying problem before attempting to solve it.
How often do we just begin coding and throwing a user interface together without having spent much, if any, time with the target audience to understand their needs, challenges, skill level and approach to solving the problem currently?

2. Make things simple.
How often do we try to put every feature we can pack into a single view thinking to make the software powerful and reduce round trips to the server or some other resource?

3. Provide context.
How often do we place controls or information in a user interface that we consider convenient but in reality is out of context and will confuse a user who does not understand what is going on “under the covers” so to speak?

4. Be consistent.
How often do we design one page in a certain way only to bounce the user to another page in a web application that uses a different design paradigm, making the user spend some time just to figure out where the OK or Cancel button or link is now?

You can read about these and the 21 principles at Whitney’s article (see link above). I also recommend the following resources, a selection from those Whitney recommends:

UX Principles and Design Guides

If you have some favorite principles of your own, please share them here.

posted on Thursday, March 25, 2010 10:25:55 AM (Mountain Daylight Time, UTC-06:00)  #    Comments [0]
# Wednesday, March 24, 2010

I’ve been giving the question of why software teams fail some considerable thought in the past few days. Reading Brad Abrams’ post Don’t Waste Keystrokes and his statement that “By far the biggest problem I see on teams of > 1 is communication” led me to compile the following list. Here are some of the reasons, in addition to the most important one that Brad pointed out already, that a software team, or any team really, fails:

  1. The team does not practice regularly, no coordinated learning.
  2. The coach does not know the strengths and weaknesses of the players.
  3. The players do not know their role, their zone or the plays.
  4. The players do not get along, they are not one in purpose.
  5. The players do not trust or respect the coaching staff.
  6. The coaching staff puts players with no skill on the starting lineup for unknown reasons causing resentment amongst the other players and guaranteeing a loss at game time.
  7. The players do not believe the coaching staff understand the game.
  8. The players are more focused on individual agendas, they do not work together to win.
  9. The rules of the game are not well understood and change during the game.
  10. The coaching staff and team captains disagree on how the game should be played.
  11. The coaching staff recruits new players looking for players who will agree with their ideas rather than seeking out players who can actually play.
  12. The players fail to improve their skills on their own time.
  13. The players lack motivation and fail to come to practice and give only a half-hearted effort in the game.
  14. The team captain spends more time arguing with the coaching staff than he does leading and motivating the players.
  15. Winning becomes secondary to just finishing the season.

If you can think of any others, please let me know. And if you have ideas for how to fix these situations, I would love to hear from you as well.

posted on Wednesday, March 24, 2010 10:06:34 AM (Mountain Daylight Time, UTC-06:00)  #    Comments [1]
# Sunday, March 14, 2010

A few years ago I worked on a project called Atrax which among other things included an implementation of the work of Yutaka Matsuo of the National Institute of Advanced Industrial Science and Technology in Tokyo and by Mitsuru Ishizuka of the University of Tokyo.

I decided to revisit the keyword extraction algorithm and update it a bit and isolate it from the overall Atrax code to make it easier for anyone to use. You can download the code Keyword.zip (17.87 KB).

Here are the top ten keywords the code returns from the Gettysburg Address and from Scot Gu’s most recent blog post:

gettys
   dedicated
   nation
   great
   gave
   dead
   rather
   people
   devotion
   people people
   lives

gu
   ASP.NET MVC
   VS 2010 and Visual Web Developer
   ASP.NET 3.5
   ASP.NET
   MVC
   Web Developer 2008 Express
   VS 2010
   VS 2008
   release
   Improved Visual Studio

Let me know if you end up using the implementation of the algorithm and if you happen to make improvements to it.

posted on Sunday, March 14, 2010 4:56:37 PM (Mountain Daylight Time, UTC-06:00)  #    Comments [0]
# Thursday, March 11, 2010

I love ASP.NET MVC 2 validations for client and server via annotations. Steve Sanderson's xVal is great too, but in this post I want to focus on a custom validation for MVC 2 which is frustratingly missing from the out-of-the-box validations. There is a very nice StringLengthAttribute which allows you to specify a maximum length but does not provide for a minimum length.

At first I attacked this deficiency with a regex like this:

[RegularExpression("[\\S]{6,}", ErrorMessage = "Must be at least 6 characters.")]
public string Password { get; set; }

This approach just seems clunky. Happily, while reading Scott Allen's piece on MVC 2 validation in MSDN magazine, I came across a critical reference to one of Phil Haack's blog posts which I must have overlooked.

Thanks go to Phil's easy to follow instructions on writing a custom validator for MVC 2 that will work on both client and server sides.

So here's my custom MinStringLengthAttribute and supporting code which let's me do something easier and cleaner like this:

[StringLength(128, ErrorMessage = "Must be under 128 characters.")]
[MinStringLength(3, ErrorMessage = "Must be at least 3 characters.")]
public string PasswordAnswer { get; set; }

If you really wanted to get creative, you could produce a combination of the two, but I'll leave that for another day.

Here's the code for the attribute and the required validator:

public class MinStringLengthAttribute : ValidationAttribute
{
  public int MinLength { get; set; }

  public MinStringLengthAttribute(int minLength)
  {
    MinLength = minLength;
  }

  public override bool IsValid(object value)
  {
    if (null == value) return true;     //not a required validator
    var len = value.ToString().Length;
    if (len < MinLength)
      return false;
    else
      return true;
  }
}

public class MinStringLengthValidator : DataAnnotationsModelValidator<MinStringLengthAttribute>
{
  int minLength;
  string message;

  public MinStringLengthValidator(ModelMetadata metadata, ControllerContext context, MinStringLengthAttribute attribute)
    : base(metadata, context, attribute)
  {
    minLength = attribute.MinLength;
    message = attribute.ErrorMessage;
  }

  public override IEnumerable<ModelClientValidationRule> GetClientValidationRules()
  {
    var rule = new ModelClientValidationRule
    {
      ErrorMessage = message,
      ValidationType = "minlen"
    };
    rule.ValidationParameters.Add("min", minLength);
    return new[] { rule };
  }
}

Here's the code in the Global.asax.cs that registers the validator:

protected void Application_Start()
{
  RegisterRoutes(RouteTable.Routes);
  DataAnnotationsModelValidatorProvider.RegisterAdapter(typeof(MinStringLengthAttribute), typeof(MinStringLengthValidator));
}

Here's the javascript to hook up the client side:

Sys.Mvc.ValidatorRegistry.validators["minlen"] = function(rule) {
  //initialization
  var minLen = rule.ValidationParameters["min"];

  //return validator function
  return function(value, context) {
    if (value.length < minLen) 
      return rule.ErrorMessage;
    else
      return true;  /* success */
  };
};

Now, in your view, add <% Html.EnableClientValidation(); %> and that's all there is to it.

posted on Thursday, March 11, 2010 1:21:29 PM (Mountain Standard Time, UTC-07:00)  #    Comments [2]
# Friday, February 05, 2010

Documentation neglect is a chronic problem in most enterprise application development efforts. This problem is unrelated to the selected development methodology but there are some who assume that agile methods eliminate documentation despite the agile manifesto's declaration that we value "working software over comprehensive documentation." It does not claim that documentation is not needed.

In my own work, I've found that comprehensive documentation authored by well meaning individuals, or worse a committee, who possess very little technical expertise, is often written in confusing, lengthy narrative style that requires a linguistic anthropologist to decipher. Too often development teams spend days pulling out the real features and requirements and expected behavior from such documents, generally resulting in many unanswered questions, the answers to which just cannot be found in the comprehensive documentation.

Recently we have found greater value in documentation that has relatively strict structures that guide authors to produce specific, detailed and comprehensible documentation. The format is simple and adopted from the increasingly popular behavior driven design (BDD) approach.

The goal of this approach is to define desired behavior and clear acceptance criteria for specific requirements without mashing them all together in a narrative style that requires time consuming decomposition. Here's the format:

+++++++++
P[n]: Process Title
Two line description of a process (akin to epic user story)

F[n]: Function Title (a feature or step in the workflow)
As a role
I want action/process description
so that benefit/value of feature.

AC[n]: Acceptance Criteria or Scenario Title (p1)
Given some initial context (the givens),
when an event occurs,
then ensure some outcomes.

+++++++++

It's really not different than BDD. There is only one subtle difference which I've found can make all the difference in the world. the terms used (process, function and acceptance criteria) are far less scary to the business than terms like epic, user story and scenario.

Of course, this won't work for every situation, but where you can break documentation down into logical units that focus on one feature, one thing at a time, you can eliminate the time consuming deconstruction of comprehensive documentation that can only be processed by the most advanced computer in the world: the human brain.

posted on Friday, February 05, 2010 3:33:35 PM (Mountain Standard Time, UTC-07:00)  #    Comments [0]
# Wednesday, January 06, 2010

This log helper class seems to get used over and over again in projects I've worked on. Generally I use it as a fallback, calling it from an exception block in a application logging code. Let me know if you find it helpful.

public static class LogHelper
{
  public static bool WriteEventLogEntry(string source, EventLogEntryType entryType, int eventId, string message)
  {
    bool passFail = true;
    try
    {
      if (!EventLog.SourceExists(source))
      {
        EventLog.CreateEventSource(source, "Application");
      }
      EventLog elog = new System.Diagnostics.EventLog();
      elog.Source = source;
      elog.WriteEntry(message, entryType, eventId);
    }
    catch
    {
      passFail = false; //this method is usually called as a last resort, so there can be no real exception handling
    }
    return passFail;
  }
}
posted on Wednesday, January 06, 2010 3:01:07 PM (Mountain Standard Time, UTC-07:00)  #    Comments [0]
# Saturday, December 12, 2009

This is an oddity with Visual Studio 2010 Beta 2 installed on the a virtual machine that I’ve run into that perhaps one in a hundred other VMWare Workstation users might run into. I’m running VMWare Workstation 6.5.3 on a Windows 7 x64 box with 8GB of RAM. In turn, I’m spinning up a Windows 7 x64 virtual machine with 3GB of RAM and two cores (a primary reason for buying the VMWare license over Virtual PC). And of course, I had 3D graphics acceleration turned on, because who wouldn’t want some acceleration, right?

But here’s what the New Project dialog and other “add” dialogs looked like (note: I’ve reduced the size of these as the nitty gritty details are not as important as the visualization of the controls, here you don’t see them and later you will):

vmvs1

Note the black (or rather dark blue) abyss at the bottom of the dialog. As near as I can tell, the normally light blue section was gone and inaccessible visually. I’m not certain, but I surmised that it was still there as I was able to tab into the darkness and then out of it again.

After trying various Windows 7 video personalization settings, I then tried increasing video memory in the VMX file, but that was a non-starter. Then an odd hunch led me to try this:

vmvs2

Once I saved that 3D graphics setting unchecked and spun up the virtual machine, I noticed two things. First, the virtual machine seemed more responsive. Second, and more importantly, controls were back in sight. This pleasing view is now what I see (minus my crudely drawn red circle of course):

vmvs3

There was a moment when I thought to blame Visual Studio 2010 Beta 2 for this anomaly but of course some brief thought and sparing a brain cell or two for reasoning and cognitive function resulted in the conclusion that something with video driver and perhaps Windows 7 or Windows in general or just my machine did not like some video setting. Happily, the 3D graphics checkbox was the first thing I tried to disable on the VMWare settings and shazam, it worked.

If you run VMWare Workstation and have problems with Visual Studio 2010 Beta 2 in your virtual machine with missing or invisible controls in certain dialogs and other UI elements, try disabling the 3D graphics option. I still highly recommend VMWare Workstation over Virtual PC, though I must admit that I have not tried Windows Virtual PC in its latest incarnation for Windows 7. The last time I tried it was in the VPC 2007 edition. If you believe the latest version has come up to par with VMWare, I’d love to hear from you.

posted on Saturday, December 12, 2009 10:50:27 AM (Mountain Standard Time, UTC-07:00)  #    Comments [0]
# Friday, December 04, 2009

I’ve not used this blog for politics in the past, but I’m going to start making some exceptions where I think there is a technology tie-in. George Will’s piece on the Copenhagen summit was very interesting. I recommend that you read it. I am not a climatologist but I am a skeptic of all science based on computer models, especially models that cannot accurately predict the present observable state of a system.

The recently hacked emails of the Climate Research Unit (CRU) in Britain reveal a pattern of behavior that would be more consistent with the corrupt leaders of a cult whose proclaimed tomes of divinely inspired scripture cannot withstand scrutiny should certain facts be revealed. In the minds of the true believing disciples or the corrupt leadership of the cult, the ends justify the means. And truth is not a consideration.  

The software models and data upon which all climate change disciples rely are written by flawed human beings. Whether a software engineer expertly writes the software to implement his best understanding of the requirements of the scientist or the real scientist writes the software with a less than perfect knowledge of software engineering and design, the outcome is the same. (Hey, not even a PhD can know everything.) All software is flawed. It is the nature of our art.

Can computer models be a good thing? Sure. Especially when they work. Can they be a bad thing? Well, consider that a climate model must model the entire earth and its atmosphere. That’s a few million data points (colossal understatement). These models must have historical data. And there’s the rub. It’s not there. Not really. So we extrapolate the data using tree cores and ice cores and, wait for it, more computer models.

Any software engineer knows that such a model will be inherently complex and that complex systems are inherently flawed and that very complex systems are inherently very flawed. No software engineer will declare her (or his) faith in such a model or its output, but more importantly, they would never bet a week’s salary on it’s accuracy without full testing and confirmation against known observable data and repeatable tests. Yet, we are preparing to bet trillions of tax payer dollars on these flawed models. “Hey, Sam, keep your hands out of my pocket!”

The problem we have is that scientists have put their faith in software models and data produced by software models as the magical source of all truth and knowledge. They are either the corrupt leaders of a cult (see the CRU emails) or its blind disciples insisting on the truth of their models even when observable facts contradict and invalidate those assertions.

The climate change models and extrapolated data have become scripture. The scientists who preach daily from the pages of that holy writ are held in prophetic awe and reverence by the ignorant masses of well intentioned politicians and citizens of the earth. Except for software engineers and the “deniers” of course.

So back to the question. Can computer models be a bad thing? Yes, when the ignorant or the corrupt use them as an unquestionable, magical affirmation of their own political agenda or emotional response to the idea that man is killing the planet and that unless we do something about it, we will all die. Well nobody wants that.

Oddly, we ridicule and persecute religious nuts who do the same thing. I guess they just weren’t smart enough to get a PhD and call themselves scientists rather than prophets. Stupid nuts.

posted on Friday, December 04, 2009 10:25:26 PM (Mountain Standard Time, UTC-07:00)  #    Comments [1]
# Sunday, November 29, 2009

It turns out that using table storage in Windows Azure 1.0 is quite easily done with a minimal amount of configuration. In the new Azure cloud service Visual Studio project template, configuration is significantly simpler than what I ended up with in a previous blog post where I was able to get the new WCF RIA Services working with the new Windows Azure 1.0 November 2009 release and the AspProvider code from the updated demo.

And while the project runs as expected on my own machine, I can’t seem to get it to run in the cloud for some reason. I have not solved that problem. Since I can’t seem to get much of a real reason for the failure via the Azure control panel, I’ve decided to start at the beginning, taking each step to the cloud rather than building entirely on the local simulation environment before taking it to the cloud for test.

I started with a clean solution. No changes except to the web role’s Default.aspx page with some static text. Publish to the cloud and twenty to thirty minutes later (too long in my opinion) the page will come up, deployment is complete and the equivalent of a “hello world” app is running in the Azure cloud.

The next step I want to experiment with is the simplest use possible of Azure table storage. In the previous project, there was a lot of configuration. In this new project, there was very little. I wondered how much of the configuration from the previous project, largely an import from the updated AspProviders demo project, was a partially unnecessary legacy of CTP bits. It turns out, nearly all of it.

Here’s the only configuration you need for accessing Azure storage:

<?xml version="1.0"?>
<ServiceConfiguration serviceName="MyFilesCloudService" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceConfiguration">
  <Role name="MyFiles">
    <Instances count="1" />
    <ConfigurationSettings>
      <!-- Add your storage account information and uncomment this to target Windows Azure storage. 
      <Setting name="DataConnectionString" value="DefaultEndpointsProtocol=https;AccountName=myacct;AccountKey=heygetyourownkey" />
      <Setting name="DiagnosticsConnectionString" value="DefaultEndpointsProtocol=https;AccountName=myacct;AccountKey=heygetyourownkey" />
      -->

      <!-- local settings -->
      <Setting name="DataConnectionString" value="UseDevelopmentStorage=true" />
      <Setting name="DiagnosticsConnectionString" value="UseDevelopmentStorage=true" />
    </ConfigurationSettings>
  </Role>
</ServiceConfiguration>

The thumbnails sample does provide one important piece of code that does not come with the standard Visual Studio template. It goes in the WebRole.cs file and makes the use of the CloudStorageAccount class’s static FromConfigurationSetting method which returns the needed CloudStorageAccount instance. To use that method, the SetConfigurationSettingPublisher method must have already been called. Hence this code placed in the WebRole class like this:

public class WebRole : RoleEntryPoint
{
  public override bool OnStart()
  {
    DiagnosticMonitor.Start("DiagnosticsConnectionString");

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

    #region Setup CloudStorageAccount Configuration Setting Publisher

    // This code sets up a handler to update CloudStorageAccount instances when their corresponding
    // configuration settings change in the service configuration file.
    CloudStorageAccount.SetConfigurationSettingPublisher((configName, configSetter) =>
    {
      // Provide the configSetter with the initial value
      configSetter(RoleEnvironment.GetConfigurationSettingValue(configName));

      RoleEnvironment.Changed += (sender, arg) =>
      {
        if (arg.Changes.OfType<RoleEnvironmentConfigurationSettingChange>()
           .Any((change) => (change.ConfigurationSettingName == configName)))
        {
          // The corresponding configuration setting has changed, propagate the value
          if (!configSetter(RoleEnvironment.GetConfigurationSettingValue(configName)))
          {
            // In this case, the change to the storage account credentials in the
            // service configuration is significant enough that the role needs to be
            // recycled in order to use the latest settings. (for example, the 
            // endpoint has changed)
            RoleEnvironment.RequestRecycle();
          }
        }
      };
    });
    #endregion

    return base.OnStart();
  }

  private void RoleEnvironmentChanging(object sender, RoleEnvironmentChangingEventArgs e)
  {
    // If a configuration setting is changing
    if (e.Changes.Any(change => change is RoleEnvironmentConfigurationSettingChange))
    {
      // Set e.Cancel to true to restart this role instance
      e.Cancel = true;
    }
  }
}

Once you have the set the configuration setting publisher, you can use the FromConfigurationSetting method in the creation of your CloudTableClient and then check for the existence of a table, creating it if it does not already exist in your repository code. Here’s a minimal example that I used and published successfully to my Azure account.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Microsoft.WindowsAzure.StorageClient;
using Microsoft.WindowsAzure;
using System.Data.Services.Client;

namespace MyDemo
{
  public class AdventureRow : TableServiceEntity
  {
    public string IpAddress { get; set; }
    public DateTime When { get; set; }
  }

  public class AdventureRepository
  {
    private const string _tableName = "Adventures";
    private CloudStorageAccount _account;
    private CloudTableClient _client;

    public AdventureRepository()
    {
      _account = CloudStorageAccount.FromConfigurationSetting("DataConnectionString");
      _client = new CloudTableClient(_account.TableEndpoint.ToString(), _account.Credentials);
      _client.RetryPolicy = RetryPolicies.Retry(3, TimeSpan.FromSeconds(1));
      _client.CreateTableIfNotExist(_tableName);
    }

    public AdventureRow InsertAdventure(AdventureRow row)
    {
      row.PartitionKey = "AdventurePartitionKey";
      row.RowKey = Guid.NewGuid().ToString();
      var svc = _client.GetDataServiceContext();
      svc.AddObject(_tableName, row);
      svc.SaveChanges();
      return row;
    }

    public List<AdventureRow> GetAdventureList()
    {
      var svc = _client.GetDataServiceContext();
      DataServiceQuery<AdventureRow> queryService = svc.CreateQuery<AdventureRow>(_tableName);
      var query = (from adv in queryService select adv).AsTableServiceQuery();
      IEnumerable<AdventureRow> rows = query.Execute();
      List<AdventureRow> list = new List<AdventureRow>(rows);
      return list;
    }
  }
}

Just as the StorageClient has moved from “sample” to first class library in the Azure SDK, I suspect that the AspProviders sample may already be on that same path to glory. In it’s current form, it represents something new and something old, the old having not been entirely cleaned up, lacking the elegance it deserves and will likely get either by Microsoft or some other enterprising Azure dev team.

As for me, I will continue trying to learn, one step at a time, why the Adventure code I blogged about previously will run locally but not on the cloud as expected. Who knows, it could be as simple as a single configuration gotcha, but figuring it out one step at a time will be a great learning opportunity and as I get the time, I’ll share what I learn here.

posted on Sunday, November 29, 2009 7:13:26 PM (Mountain Standard Time, UTC-07:00)  #    Comments [0]