# 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]
# Monday, November 23, 2009

A month ago I posted the results of some experimentation with the preview bits of what was then called .NET RIA Services, Silverlight 3 and the Windows Azure with AspProvider sample code from the Azure July 2009 CTP. That was then and much has changed.

Windows Azure 1.0 and what is now called WCF RIA Services Beta have since been released. Lot’s of great changes make using these together with the new AspProvider sample in the “Additional C# Samples” download that some friendly readers shared with me. With Visual Studio 2008 SP1 and SQL Server 2008 (Express if you want) and these you’re set up to play.

WARNING: They were not lying about the WCF part when they renamed it. The default Domain Service channel is binary and they’re using Windows Activation Service (WAS). So make sure you’re Windows Features look something like this or you’re in for several hours of maddening error chasing.

advnew3

After some review of the previous effort using the July 2009 CTP and RIA preview bits, I decided starting over was the best course of action. Here’s the steps to nirvana:

  1. Create a new Silverlight Business Application called Adventure which produces Adventure.Web application as well.
  2. Add new CloudService project with WebRole called AdventureCloudService and WebRole1.
  3. Copy WebRole.cs to Adventure.Web and rename namespace.
  4. Add 3 azure refs to Adventure.Web.
  5. In the cloud service project file, replace WebRole1 with Adventure.Web and project guid with that from Adventure.Web. (There is probably a better way to do this.)
  6. The node under Roles in the cloud service project shows an error. Right click it and choose “associate” and pick Adventure.Web.
  7. Copy system.diagnostics section from WebRole1 web.config to that of Adventure.Web.
  8. Remove WebRole1 from solution and set service project as startup.
  9. Copy and new AspProviders project and sections from demo web.config into Adventure.Web, changing DefaultProviderApplicationName and applicationName="Adventure".
  10. Do the same previous steps to create/copy UserProfile class and IUserProfile with FriendlyName property too. Added to the Models directory this time. NOTE: Be sure to get the magic strings right in the UserProfile class or you will get unexpected results.
  11. Add Global.asax and AppInitializer class to it from previous project without the CreateTableFromModel calls which are no longer needed as I understand it.
  12. Drop in the code to create the admin user if it does not already exist.
  13. When I go to modify the LoginStatus.xaml which was previously LoginControl.xaml, but find the needed modification is already there. Skip this step.
  14. Just hit F5 and error is thrown.

After some lengthy research, I discovered a bug in the AspProvider's TableStorageRoleProvider.cs. When the RoleExists method is called and no roles have yet been created an exception is thrown.

AspProvider Fix Found
Replace e.InnerException in line 484 in TableStorageRoleProvider.cs with e.InnerException.InnerException. The first inner exception is another InvalidOperationException. The second inner exception is the DataServiceClientException we're looking for.

Login with admin/admin and we see Administrator displayed in the newly renamed LoginStatus area.

And we’re back to par. Download the code here (566KB).

posted on Monday, November 23, 2009 8:48:05 PM (Mountain Standard Time, UTC-07:00)  #    Comments [0]
# Sunday, November 22, 2009

Silverlight WCF RIA Services Beta Released was released recently, replacing the preview bits I’ve been playing with. You can pick up the new beta here. I'm still using VS 2008 SP1, but I am using Windows 7, so I download directly from here.

WARNING! If you’re not on Windows 7 or Server 2008 R2, you’ll need the hotfix mentioned. If you're still on XP or Vista, let this be the final reason to upgrade and do it. You won't regret it.

I learned first about the beta release from Dan Abrams blog post. Some coolness he mentions:

  • DataSources window. Drag and drop "tables" exposed by Domain Service onto the form.
  • Simplified error handling on client and server.
  • Data model inheritence flows through the Domain Service.
  • Presentation model hides DAL model with CRUD support.
  • Optimized binary channel by default.
  • Integrated into Silverlight 4 installer.
  • Handling of compositional hiearchy in data models.
  • GAC and bin deployment, with bin taking precedence.
  • Globalization support, user state and persisted sign in with updated Business Application Template.
  • Go-Live bits for .NET 3.5 SP1 and Silverlight 3.

Another item of note is the name change with the WCF moniker. RIA Services is now part of the WCF services family along with ADO.NET Data Services. This seems like a convergence of technologies in an enterprise ready set of tools and services that will bring Silverlight into the forefront of enterprise application development and delivery.

I'll be working on pulling these new bits together and getting my "Aventure" blog sample back on track with the new Azure SDK bits and these new WCF RIA Services bits. Given the plethora of changes, I'll likely start over with fresh new project templates and pull what little customized code that might be needed from my previous blog post on the topic.

posted on Sunday, November 22, 2009 1:50:42 PM (Mountain Standard Time, UTC-07:00)  #    Comments [0]
# Sunday, November 15, 2009

The 1.0 release of Windows Azure SDK is now available. Download and read about what’s new here. Sadly, the AspProviders sample project was not included. I spent a few hours trying to bandage it up, but it was a hopeless cause. If a new AspProviders sample is not soon forthcoming, it will be easier to write one from scratch using the new SDK and the new project templates.

Update (11/22/09) - AspProviders in Additional C# Examples: One comment and an additional private email from readers have pointed out Azure Code Samples on MSDN where you can download the "Additional C# Samples" which contatin the new AspProviders. I'll be checking out this and other samples with the new Azure SDK. Thanks to both Jason and Gerold for the links.

When I tried to run my old project, after modifying some references to match those of a fresh project created with the new Visual Studio templates, the first thing that popped was a new local storage database script dialog result:

az-nov09-01 

I’ve not explored them in detail but there are several new tables, some stored procedures and a few user defined functions in the new dev storage database.

I clicked okay and before I got my next error, I noticed the new baloon dialog name for the dev fabric, Windows Azure Simulation Environment:

az-nov09-02

I also compared the csCFG and and csDEF config files for the Azure cloud service project. The XML namespace is the same and as near as I can tell there are no changes there.

The next thing I noticed was a new class in the web role of the new project template. Seems we now have a “Windows Service”-like OnStart and RoleEnironmentChanging set of startup and status change event handlers. This will be highly useful for web role applications that may have resource cleanup needs.

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;

		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;
		}
	}
}

Another bit of great news is that the StorageClient goes from “sample” project to part of the release libraries. There were ample changes there which appear to have broken the AspProviders sample project severely. While that explains the missing AspProviders project disappointment, I do hope that it means the changes in the StorageClient namespace will make using Azure storage easier.

Much more to learn and blog about with the new release, but it looks as though I’ll need to start over on my “Aventure” sample. I’m glad that I don’t have loads of code to refactor to the new release. It makes starting over less painful. For those who have written large projects relying on the beta, all I can say is, “beta = subject to change.”

posted on Sunday, November 15, 2009 3:42:06 PM (Mountain Standard Time, UTC-07:00)  #    Comments [1]
# Wednesday, October 21, 2009

A very long time ago, I wrote a little helper class clone of SqlHelper for Oracle which I called OraHelper. I haven’t looked at or touched the code in years, but I regularly get email asking where it’s gone to. It appears that the www.asp.net community gallery still refers to it but their link is broken. Rather than attempt to get them to fix the link, I’m posting it here.

Download OraHelper (12KB) here.

I don’t know how well this code works anymore. I’ve no Oracle database against which I can test it. I recall that one inquirer indicated that he wanted the code because he was limited to the .NET Framework 1.1. I found that rather sad to think about given how comfortable I’ve become with generics and lambdas of late.

For those of you who are doing .NET database access to Oracle, you may be helped even more by looking at Oracle’s .NET Developer Center. I can’t speak for the state of their current support. Perhaps there are readers that could post more informed comments on the subject here.

posted on Wednesday, October 21, 2009 9:05:51 AM (Mountain Daylight Time, UTC-06:00)  #    Comments [0]
# Sunday, October 18, 2009

After spending last weekend working on and blogging about Silverlight 3 and .NET RIA services, I decided I’d look to build out a membership, profile and role provider that would use Windows Azure storage. Much to my delight, I stumbled into the AspProvidersDemo code that comes with the Windows Azure SDK or perhaps the Visual Studio 2008 Tools for Azure.

No matter, you need them both to follow along with this post. If you have not already, you should look at my previous post and make sure you prepare your environment for Silverlight 3 in addition to signing up for your Azure account and installed the tools mentioned

You can download the entire solution file (434KB) and skip to the momentous striking of your F5 key if you like. Or you can follow along here and blunder through this adventure as I did. (I recommend cheating now and downloading the code.)

Here’s the step-by-step details. I’ll try to spare the you excruciating minutiae and keep it as exciting as possible.    

I started by creating a standard Cloud Service application called MyFilesCloudService with a web role called WebFilesRole. I then added a Silverlight Business Application called Adventure. Unfortunately, this template does not allow you to select the web role application to host the Silverlight app.

I removed the Adventure.Web application and in the web role’s project properties added the Silverlight app in the Silverlight Application tab. (ERROR: This turned out to be a problem which I solved by added a throwaway standard Silverlight app to the solution, selecting the WebFilesRole app as the host. I am still not certain why, but I’ll spare you the grisly details of experimentation with the web.config. If you haven’t already, this is a good place to stop and download the code.)

I copied the AspProviders and StorageClient projects from the Azure SDK demos folder into the solution directory and added them to the solution. I also copied the relevant sections from the web.config for the web role and the ServiceConfiguration.cscfg and ServiceDefinition.csdef files in cloud service project.

I hit F5 for kicks and get (via Event Viewer) an event 3007, “A compilation error has occurred.” Upon further digging I realize that the profile provider is configured to inherit it’s ProfileBase from UserProfile. The class is in the demo’s web role. Steal that too. Here it is as added to the web role in my project:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Profile;
using System.Web.Security;

namespace WebFilesRole
{
   public class UserProfile : ProfileBase
   {
      public static UserProfile GetUserProfile(string username)
      {
         return Create(username) as UserProfile;
      }

      public static UserProfile GetUserProfile()
      {
         return Create(Membership.GetUser().UserName) as UserProfile;
      }


      [SettingsAllowAnonymous(false)]
      public string Country
      {
         get { return base["Country"] as string; }
         set { base["Country"] = value; }
      }

      [SettingsAllowAnonymous(false)]
      public string Gender
      {
         get { return base["Gender"] as string; }
         set { base["Gender"] = value; }
      }

      [SettingsAllowAnonymous(false)]
      public int Age
      {
         get { return (int)(base["Age"]); }
         set { base["Age"] = value; }
      }
   }
}

I boldly hit F5 again and get this gem:

Configuration Error
Initialization of data service structures (tables and/or blobs) failed!
The most probable reason for this is that the storage endpoints are not configured correctly.
Line 133: type="Microsoft.Samples.ServiceHosting.AspProviders.TableStorageSessionStateProvider"

A little searching and googling and I learn that I need to right-click on my cloud service application and select “Create Test Storage Tables.” I do it and bada-bing, I get this nice dialog and Output window text:

advent3

DevTableGen : Generating database 'MyFilesCloudService'
DevTableGen : Generating table 'Roles' for type 'Microsoft.Samples.ServiceHosting.AspProviders.RoleRow'
DevTableGen : Generating table 'Sessions' for type 'Microsoft.Samples.ServiceHosting.AspProviders.SessionRow'
DevTableGen : Generating table 'Membership' for type 'Microsoft.Samples.ServiceHosting.AspProviders.MembershipRow'
===== Create test storage tables succeeded =====

Aha! I go examine my local SQL Server instance and sure enough, there’s a new DB called MyFilesCloudService with some interesting tables. You can take at look at your own when you’ve read far enough along here to learn to click that “Create Test Storage Tables” magic context menu item too.

So I experiment a little and create a couple of test tables like this:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Microsoft.Samples.ServiceHosting.StorageClient;

namespace WebFilesRole
{
   public class MyTestDataServiceContext : TableStorageDataServiceContext
   {
      public IQueryable Roles
      {
         get
         {
            return this.CreateQuery("MyTest");
         }
      }
   }

   public class MyTestRow : TableStorageEntity
   {
      public string MyTestName { get; set; }
   }
}

Note the nice and easy TableStorageEntity and it’s TableStorageDataServiceContext. Just don’t make the mistake I did and forget to name the property something unique. I tried Roles (yeah, a copy/past error) and got a nasty message like this:

No table generated for property 'Roles' of class 'WebFilesRole.MyTestDataServiceContext' because the name matches (or differs only in case) from the name of a previously generated table

I add an AppInitializer class to make sure these tables get created in the cloud when run there. First, I add a bit of code to the Application_BeginRequest method in the Global.asax.cs (the one I just added but didn’t tell you about).

protected void Application_BeginRequest(object sender, EventArgs e)	
{	
   HttpApplication app = sender as HttpApplication;   
   if (app != null)   
   {   
      HttpContext context = app.Context;   
      AppInitializer.Initialize(context);   
   }   
}

I then add the initializer class at the bottom of that same code file.

internal static class AppInitializer
{
   static object lob = new object();
   static bool alreadyInitialized = false;
   public static void Initialize(HttpContext context)
   {
      if (alreadyInitialized) return;
      lock (lob)
      {
         if (alreadyInitialized) return;
         InitializeAppStartFirstRequest(context);
         alreadyInitialized = true;
      }
   }

   private static void InitializeAppStartFirstRequest(HttpContext context)
   {
      StorageAccountInfo account = StorageAccountInfo.GetDefaultTableStorageAccountFromConfiguration();
      TableStorage.CreateTablesFromModel(typeof(Microsoft.Samples.ServiceHosting.AspProviders.MembershipRow));
      TableStorage.CreateTablesFromModel(typeof(Microsoft.Samples.ServiceHosting.AspProviders.RoleRow));
      TableStorage.CreateTablesFromModel(typeof(Microsoft.Samples.ServiceHosting.AspProviders.SessionRow));
      TableStorage.CreateTablesFromModel(typeof(Room));
   }
}

I then add some test code into the Default.aspx.cs which I won’t bore you with here. You can look at it in the downloaded solution. I got a weird error with the session test, but after a reboot, it went away, so I’ll chalk that up to the development fabric being a CTP.

Now I want to get back to working Silverlight into the picture. I need to create an admin user for my test login, so I add some code to the AppInitializer class in the Global.asax.cs file like this:

MembershipUser user = Membership.GetUser("admin");
if (null == user)
{
   //create admin user
   MembershipCreateStatus status = MembershipCreateStatus.Success;
   Membership.CreateUser("admin", "admin", "admin@admin.com", "admin-admin", "admin", 
      true, Guid.NewGuid(), out status);

   //add admin user to admin role
   if (status == MembershipCreateStatus.Success)
   {
      if (!Roles.RoleExists("admin"))
      {
         Roles.CreateRole("admin");
      }
      Roles.AddUserToRole("admin", "admin");
   }

   //add profile data to admin user
   UserProfile profile = UserProfile.Create("admin") as UserProfile;
   profile.Age = 40;    //not my true age
   profile.Country = "US";
   profile.Gender = "M";
   profile.Save();
}

I look at the UserProfile class and know that the DomainService’s User class needs the same properties in order for the Silverlight RiaContext to know about them. I discovered in the metadata code the following comments in the UpdateUser method of the  System.Web.Ria.ApplicationServices.AuthenticationBase<T> base class used for the AuthenticationService domain service class:

// Remarks:
//     By default, the user is persisted to the System.Web.Profile.ProfileBase.
//     In writing the user to the profile, the provider copies each property in
//     T into the corresponding value in the profile. This behavior can be tailored
//     by marking specified properties with the System.Web.Ria.ApplicationServices.ProfileUsageAttribute.

I know now that I want the UserProfile and the User classes to have the same profile properties, so I add an interface above the UserProfile class like this:

public interface IUserProfile	
{	
   string Country { get; set; }   
   string Gender { get; set; }   
   int Age { get; set; }   
}

And then add the same properties found in UserProfile to the User class in the AuthenticationService.cs file as follows:

public class User : UserBase, IUserProfile   
{   
   // NOTE: Profile properties can be added for use in Silverlight application.   
   // To enable profiles, edit the appropriate section of web.config file.   
   
   // public string MyProfileProperty { get; set; }   
   
   public string Country { get; set; }   
   
   public string Gender { get; set; }   
   
   public int Age { get; set; }   
}

I try to run it and get the following error on the Silverlight app when I try to login using admin/admin: "The specified resource was not found." A little digging reveals that I need two things: first, some additions to the web.config file that I was missing, and second, the ServiceDefinition.csdef had to have it’s enableNativeCodeExecution set to true. Here’s the pieces:

<!-- handlers and httpHandlers sections require the following additions -->
<handlers>
   <add name="DataService" verb="GET,POST" path="DataService.axd" type="System.Web.Ria.DataServiceFactory, System.Web.Ria, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>		
</handlers>

<httpHandlers>
   <add path="DataService.axd" verb="GET,POST" type="System.Web.Ria.DataServiceFactory, System.Web.Ria, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" validate="false"/>		
</httpHandlers>

<!-- the ServiceDefinition.csdef gets the enableNativeCodeExecution set to true -->
<WebRole name="WebFilesRole" enableNativeCodeExecution="true">

Once those changes were made, I was able to run the Silverlight application, login using admin/admin and logout. Now one more item on the agenda for this post. I want to see the profile information we added in the AppInitializer code. So I modify the LoginControl.xaml and LoginControl.xaml.cs as follows.

<StackPanel x:Name="logoutControls" Style="{StaticResource LoginPanelStyle}">
   <TextBlock Text="welcome " Style="{StaticResource WelcomeTextStyle}"/>
   <TextBlock Text="{Binding Path=User.Name}" Style="{StaticResource WelcomeTextStyle}"/>
      <TextBlock Text="  |  " Style="{StaticResource SpacerStyle}"/>
      <TextBlock Text="" x:Name="ProfileText" Style="{StaticResource WelcomeTextStyle}"/>
      <TextBlock Text="  |  " Style="{StaticResource SpacerStyle}"/>
   <Button x:Name="logoutButton" Content="logout" Click="LogoutButton_Click" Style="{StaticResource LoginRegisterLinkStyle}" />
</StackPanel>

With the code behind changed like this:

private void UpdateLoginState()	
{	
   if (RiaContext.Current.User.AuthenticationType == "Windows")   
   {   
      VisualStateManager.GoToState(this, "windowsAuth", true);   
   }   
   else //User.AuthenticationType == "Forms"   
   {   
      VisualStateManager.GoToState(this,    
         RiaContext.Current.User.IsAuthenticated ? "loggedIn" : "loggedOut", true);   
   
      if (RiaContext.Current.User.IsAuthenticated)   
      {   
         this.ProfileText.Text = string.Format("age:{0}, country:{1}, gender:{2}",    
            RiaContext.Current.User.Age,    
            RiaContext.Current.User.Country,    
            RiaContext.Current.User.Gender);   
      }   
   }
}

Now when I login, I get to look at something like this:

advent8

Cool. In Part 2, I’ll modify the UserProfile to capture the data I want to keep in my Adventure application and complete the user registration changes to the Silverlight application as well as clean up and prepare the app for some real application development in follow-on posts.

If you have any questions or ways to do this better, I’d love to hear from you.

posted on Sunday, October 18, 2009 7:58:29 PM (Mountain Daylight Time, UTC-06:00)  #    Comments [0]
# Monday, October 12, 2009

I finally carved out some time to experiment with Silverlight 3 and .NET RIA Services over the weekend. Specifically I wanted to experiment with Forms security and how one might secure a Silverlight "page" as well as the services on the server side along with a custom membership, role and profile providers. Here's the result.

Tools
Before you follow along on your own machine, be sure that you have these:

1. Visual Studio 2008 Pro (Visual Studio 2008 Professional Edition (90-day Trial))

2. Visual Studio 2008 SP1 (Microsoft Visual Studio 2008 Service Pack 1 (Installer))

3. Silverlight SDK (Microsoft® Silverlight™ 3 Tools for Visual Studio 2008 SP1)

4. RIA Services July 2009 Preview (Microsoft .NET RIA Services July 2009 Preview)

5. Download code for this post (download DemoAgRia.zip 427KB).

Once you have the tools installed, you can start a new Visual Studio project from the Silverlight projects types called Silverlight Business Application. Name yours whatever you like. I've chosen DemoAgRia.

s1

The project template creates a Silverlight and ASP.NET Web Application project and populates them with a number of helpful artifacts to get us started. There are two DomainService classes, one for authentication and one for user registration. These services use the standard ASP.NET Membership, Role and Profile provider model.

s2

You also get several "views" or Page and ChildWindow XAML controls with code-behind. These files are a familiar construct to any classic ASP.NET developer. Of course XAML is a whole new ballgame compared to the hodge podge of HTML. But rather than focus on these page and child window objects, I will focus this post on the security aspects of the app.

While the project template sets authentication to "Forms" based authentication there are no membership, role, or profile providers configured in the web.config. Since I'm going to create some custom providers in order to just experiment with the mechanics of security within the Silverlight and the web app, I'll just spin up some stub providers. Here's the web.config sections (including the "Forms" authentication node) for them:

<authentication mode="Forms"/>

<roleManager enabled="true" defaultProvider="AgRoleProvider">
  <providers>
    <clear />
    <add name="AgRoleProvider" type="DemoAgRia.Web.AgRoleProvider" />
  </providers>
</roleManager>
<membership defaultProvider="AgMembershipProvider">
  <providers>
    <clear />
    <add name="AgMembershipProvider" type="DemoAgRia.Web.AgMembershipProvider" />
  </providers>
</membership>
<profile enabled="true" defaultProvider="AgProfileProvider">
  <providers>
    <clear />
    <add name="AgProfileProvider" type="DemoAgRia.Web.AgProfileProvider" />
  </providers>
  <properties>
    <clear />
    <add name="PhoneNumber" />
    <add name="FullName" />
  </properties>
</profile>

Now I stub out the provider classes in the Providers folder of the web application. I won't post the code here because the implementation provides dumb data or place holders. Of course, a real set of providers, whether you use the AspSqlMembership provider or role your own, will do real authentication and provide real role and profile access. The stub membership class will authenticate any username and password to allow us to just play with the happy path for now.

Note the custom properties I've added to the profile provider above. These require some custom code in two places. First, in the profile provider class and then in the User class found in the AuthenticationService.cs file. Here's the code for both:

in AgProfileProvider.cs:

public override SettingsPropertyValueCollection GetPropertyValues(SettingsContext context, 
  SettingsPropertyCollection collection)
{
  string userName = context["UserName"].ToString(); //use this to look up real values for user

  SettingsPropertyValueCollection s = new SettingsPropertyValueCollection();
  foreach (SettingsProperty p in collection)
  {
    if (p.Name == "PhoneNumber") s.Add(new SettingsPropertyValue(p) { PropertyValue = "508.555.1212" });
    if (p.Name == "FullName") s.Add(new SettingsPropertyValue(p) { PropertyValue = "Tyler Jensen" });
    //NOTE: replace with real lookups
  }
  return s;
}
in AuthenticationService.cs:

public class User : UserBase
{
  // NOTE: Profile properties can be added for use in Silverlight application.
  // To enable profiles, edit the appropriate section of web.config file.

  // public string MyProfileProperty { get; set; }
  public string FullName { get; set; }
  public string PhoneNumber { get; set; }
}

Now to use these new profile provider properties, let's modify some XAML in the LoginControl.xaml file so that rather than seeing the username of the logged in user, we'll see the FullName and the PhoneNumber.

Here's the existing XAML which we will modify:

<StackPanel x:Name="logoutControls" Style="{StaticResource LoginPanelStyle}">
  <TextBlock Text="welcome " Style="{StaticResource WelcomeTextStyle}"/>
  <TextBlock Text="{Binding Path=User.Name}" Style="{StaticResource WelcomeTextStyle}"/>
  <TextBlock Text="  |  " Style="{StaticResource SpacerStyle}"/>
  <Button x:Name="logoutButton" Content="logout" Click="LogoutButton_Click" Style="{StaticResource LoginRegisterLinkStyle}" />  
</StackPanel>

We now modify this XAML snippet to this:

 
<StackPanel x:Name="logoutControls" Style="{StaticResource LoginPanelStyle}">
  <TextBlock Text="welcome " Style="{StaticResource WelcomeTextStyle}"/>
  <TextBlock Text="{Binding Path=User.FullName}" Style="{StaticResource WelcomeTextStyle}"/>
  <TextBlock Text="  |  phone: " Style="{StaticResource SpacerStyle}"/>
  <TextBlock Text="{Binding Path=User.PhoneNumber}" Style="{StaticResource WelcomeTextStyle}"/>
  <TextBlock Text="  |  " Style="{StaticResource SpacerStyle}"/>
  <Button x:Name="logoutButton" Content="logout" Click="LogoutButton_Click" Style="{StaticResource LoginRegisterLinkStyle}" />
</StackPanel>

Now lets add a DomainService for fecthing some data. Right click on the web application's Services folder and select Add | New Item.

s3

Of course, we don't have a data or object context class, so we don't have any to choose from in the dialog.

s4

Leave "Enable client access" checked. We want a proxy class to automatically be generated from our service class on the server side. Just click OK and let's create our own custom DomainService.

Now you'll see something like this:

 
namespace DemoAgRia.Web.Services
{
  using System;
  using System.Collections.Generic;
  using System.ComponentModel;
  using System.ComponentModel.DataAnnotations;
  using System.Linq;
  using System.Web.Ria;
  using System.Web.Ria.Data;
  using System.Web.DomainServices;


  // TODO: Create methods containing your application logic.
  [EnableClientAccess()]
  public class DemoDataService : DomainService
  {
  }
}

I'll put it into the root of the namespace by lopping off the ".Services" in the namespace declaration. This is just a convenience to me. You can do with it what you like.

Now let's add a couple of simplistic methods. Be sure to decorate them with the ServiceOperation attribute or the build process will not autogenerate the DemoDataContext class and proxy class in the Silverlight client app.

 
[EnableClientAccess()]
public class DemoDataService : DomainService
{
  [ServiceOperation]
  public string GetApplicationName()
  {
    return "Demo Ag Ria";
  }

  [ServiceOperation]
  public string GetApplicationAddress()
  {
    return "http://www.demoagria.com";
  }
}

To use the DemoDataService on the client, let's try the following code in the Home.xaml.cs file. Note the two additional using statements and take special note that all calls to the server are asynchronous:

 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Data;
using System.IO;
using DemoAgRia.Web;
using System.Windows.Ria.Data;

namespace DemoAgRia
{
  public partial class Home : Page
  {
    public Home()
    {
      InitializeComponent();
    }

    // Executes when the user navigates to this page.
    protected override void OnNavigatedTo(NavigationEventArgs e)
    {
      DemoDataContext ddc = new DemoDataContext();
      InvokeOperation<string> invAddress = ddc.GetApplicationAddress();
      invAddress.Completed += new EventHandler(invAddress_Completed);
      
      InvokeOperation<string> invAppName = ddc.GetApplicationName();
      invAppName.Completed += new EventHandler(invAppName_Completed);
    }

    void invAppName_Completed(object sender, EventArgs e)
    {
      InvokeOperation<string> op = sender as InvokeOperation<string>;
      string appName = op.Value;
      this.ContentText.Text += string.Format("{0}app name: {1}", Environment.NewLine, appName);
    }

    void invAddress_Completed(object sender, EventArgs e)
    {
      InvokeOperation<string> op = sender as InvokeOperation<string>;
      string address = op.Value;
      this.ContentText.Text += string.Format("{0}address: {1}", Environment.NewLine, address);
    }

  }
}

If you F5 and run a debug test, you'll note that the text in the Home page gets modified as expected.

s5

Now let's add a RequiresAuthentication to the GetApplicationName method:

[ServiceOperation, RequiresAuthentication]
public string GetApplicationName()
{
  return "Demo Ag Ria";
}

Run the app again and you will notice that the GetApplicationName's InvokeOperation<string> object's Value property is null. Now login and click the About page link and then go back to the Home page link. Note that the text has maintained it's state. We're not clearing it, but this time we've added text which includes the app name.

s6

Now try modifying the GetApplicationAddress method like this:

[ServiceOperation, RequiresRoles("Supervisor")]
public string GetApplicationAddress()
{
  return "http://www.demoagria.com";
}

Since the stubbed role provider gives your logged in user the Admin and Analyst role, you can run this and see that you are getting a null value for the operation. Now change the role to "Admin" and try the same thing. This time when you login and come back to the Home page you'll see what we'd expect.

Getting this far was almost enough fun, but then I wondered how I would prevent a user from navigating to a specific Silverlight page if they were not authenticated. There are probably better ways, but here's the solution I arrived at after a little fiddling.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Navigation;

namespace DemoAgRia
{
  public class PageSecurity
  {
    private Page page;
    private string url;

    public PageSecurity(Page page)
    {
      this.page = page;
    }

    public void Authenticate()
    {
      Authenticate(null);
    }

    public void Authenticate(string url)
    {
      this.url = url;
      if (!RiaContext.Current.User.IsAuthenticated)
      {
        ErrorWindow ew = new ErrorWindow("You must be logged in to view this page.", 
          "Using this page is not allowed unless you are logged in.");
        ew.Title = "Authentication Required";
        ew.IntroductoryText.Text = "Not Authenticated";
        ew.LabelText.Text = "Message";
        ew.Closed += new EventHandler(ew_Closed);
        ew.Show();
      }
    }

    void ew_Closed(object sender, EventArgs e)
    {
      if (null == url)
        this.page.NavigationService.GoBack();
      else
      {
        if (!url.StartsWith("/")) url = "/" + url;
        try
        {
          this.page.NavigationService.Navigate(new Uri(url, UriKind.Relative));
        }
        catch
        {
          this.page.NavigationService.GoBack(); 
        }
      }
    }
  }
}

To test this code, I've added the following code to the About.xaml.cs code to see how it plays.

protected override void OnNavigatedTo(NavigationEventArgs e)
{
  PageSecurity ps = new PageSecurity(this);
  ps.Authenticate("Home");
}

Now all you have to do is download the code and you've got a headstart on Silverlight and .NET RIA Services security. Let me know if you find any exciting improvements or alternatives.

posted on Monday, October 12, 2009 3:01:52 PM (Mountain Daylight Time, UTC-06:00)  #    Comments [0]