OraHelper – An Oracle Version of the SqlHelper Class

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.

Building Enterprise Applications with Silverlight 3, .NET RIA Services and Windows Azure Part 1

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.

Silverlight 3 and .NET RIA Services Forms Security

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.

Enum to Dictionary with Description Attribute Reflection

A week ago in a misguided attempt to make things easier, I created something like the following code. My mistake was not in creating the code necessarily, but in applying it to data driven auto generated enums. If you have those, don’t use this.

If you have nice, well behaved static enums wandering around your code and you wish you had a nice way to convert that enum to a usable Dictionary<int, string>, then you’ve come to the right place. So dress up that drab enum with a Description attribute like you see below and call EnumConverter.ConvertToDictionary<DrabEnum>();

And let me know how it works out.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Data.Linq;
using System.Text;
using System.Reflection;
using System.Collections;

namespace FunStuff
{
  public enum FunEnum
  {
    [Description("Happy Enum")]
    Happy = 1,

    [Description("Sad Enum")]
    Sad = 2
  }


  public static class EnumConverter
  {
    private static object lo = new object(); //used for locking access to the Cache
    private static Dictionary<Type, Dictionary<int, string>> enumStore = 
      new Dictionary<Type, Dictionary<int, string>>();

    /// <summary>
    /// Returns thread safe copy of enum value and name dictionary. Where Description <br />
    /// attribute exists, returns the description value.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <returns></returns>
    public static Dictionary<int, string> ConvertToDictionary<T>() where T : IComparable
    {
      lock (lo)
      {
        Type t = typeof(T);
        if (!t.IsEnum) throw new ArgumentException("T must be an enum.");
        if (!enumStore.ContainsKey(t)) enumStore.Add(t, Load(t));
        return new Dictionary<int, string>(enumStore[t]);
      }
    }

    private static Dictionary<int, string> Load(Type t)
    {
      Dictionary<int, string> list = new Dictionary<int, string>();
      foreach (MemberInfo m in t.GetMembers())
      {
        if (m.MemberType == MemberTypes.Field && m.Name != "value__")
        {
          string label = m.Name;
          foreach (var att in m.GetCustomAttributes(false))
          {
            DescriptionAttribute da = att as DescriptionAttribute;
            if (null != da)
            {
              if (da.Description.Length > 0)
              {
                label = da.Description;
              }
            }
          }
          int id = Convert.ToInt32(System.Enum.Parse(t, m.Name));
          list.Add(id, label);
        }
      }
      return list;
    }
  }
}

PLINQO a Better LINQ to SQL

A few weeks ago I made a major course correction in our choice of ORM data layer. We had planned to use LLBLGen Pro but several issues with the code that it generates continued to bother me. First, it's support for stored procedures lacked the ability to strongly type the resultset. Second, the data entity classes do not easily support serialization over WCF with the option to dress them up with the appropriate attributes.

So I took a second look at PLINQO with CodeSmith 5.0, something I had considered some time ago but had decided against because I felt it was not sufficiently mature for our team's use. I wanted to see if the dev team had improved the product to the point that I believed it would work for us. I'm very happy I gave it another try. They have done a great job and restored my confidence in LINQ to SQL.

With PLINQO, I found that I could return to standard LINQ to SQL queries and enjoy many of the benefits I had looked forward to using in LLBLGen Pro such as "disconnected" entities. And much to my satisfaction, PLINQO resolves the two major issues I had with the LLBLGen Pro. The improvements over standard LINQ to SQL may seem small at first but when dealing with a very large, enterprise class database, the enhancements that PLINQO offers are critical, including the separation of entities into individual class files.

There are many more features and benefits with PLINQO than I have time to review here. If you're looking for a better LINQ to SQL than LINQ to SQL, look very carefully at PLINQO. I mean, who couldn't fall in love with code like this all buttoned up for you automatically:

private long _userId;

//// <summary>
/// Gets the USER_ID column value.
/// </summary>
[System.Data.Linq.Mapping.Column(Name = "USER_ID", Storage = "_userId", 
     DbType = "bigint NOT NULL IDENTITY", IsPrimaryKey = true, 
	 IsDbGenerated = true, CanBeNull = false)]
[System.Runtime.Serialization.DataMember(Order = 1)]
public long UserId
{
    get { return _userId; }
    set
    {
        if (_userId != value)
        {
            OnUserIdChanging(value);
            SendPropertyChanging("UserId");
            _userId = value;
            SendPropertyChanged("UserId");
            OnUserIdChanged();
        }
    }
}

Enforce WCF Proxy Net.Tcp Config in Code

In a recent project I wanted to simplify the creation and configuration of a WCF proxy client and enforce programmatic configuration so that the client could only be used in a specific configuration. Here’s the result of that effort. Note that there is a static Create method and the standard ClientBase constructors have been marked as internal to prevent creation of the client in any other way.

public class ControlServiceClient : ClientBase<IControlService>, IControlService
{
    public static ControlServiceClient Create()
    {
        string controlServiceAddress = ConfigurationManager.AppSettings["controlServiceAddress"];
        NetTcpBinding tcpBinding = new NetTcpBinding(SecurityMode.Transport, false);
        tcpBinding.Security.Transport.ClientCredentialType = TcpClientCredentialType.Windows;
        tcpBinding.Security.Transport.ProtectionLevel = ProtectionLevel.EncryptAndSign;

        //set other binding attributes
        tcpBinding.CloseTimeout = new TimeSpan(0, 1, 30);     //default is 1 minute.
        tcpBinding.MaxBufferPoolSize = 1048576;               //1MB default is 65,536 bytes

        //not allowed by partially trusted 
        //tcpBinding.MaxBufferSize = 262144;                  //256KB default is 65,536 bytes

        tcpBinding.MaxConnections = 10;                       //default is 10:
        tcpBinding.MaxReceivedMessageSize = 4194304;          //4MB The default is 65,536 bytes
        tcpBinding.OpenTimeout = new TimeSpan(0, 1, 30);      //The default value is 1 minute
        tcpBinding.ReceiveTimeout = new TimeSpan(0, 10, 0);   //The default value is 10 minute
        tcpBinding.SendTimeout = new TimeSpan(0, 1, 30);      //The default value is 1 minute

        EndpointAddress endpointAddress = 
            new EndpointAddress(string.Format("net.tcp://{0}", controlServiceAddress));
        ControlServiceClient client = new ControlServiceClient(tcpBinding, endpointAddress);
        return client;
    }

    internal ControlServiceClient() { }

    internal ControlServiceClient(string endpointConfigurationName) :
        base(endpointConfigurationName)
    { }

    internal ControlServiceClient(Binding binding, EndpointAddress remoteAddress) :
        base(binding, remoteAddress)
    { }

    internal ControlServiceClient(InstanceContext callbackInstance) :
        base(callbackInstance)
    { }

    public string GetData(int value)
    {
        return base.Channel.GetData(value);
    }

    public CompositeType GetDataUsingDataContract(CompositeType composite)
    {
        return base.Channel.GetDataUsingDataContract(composite);
    }
}

Base 30 Type in C#

I'm experimenting with using the Guid type in databases and applications but I don't like the string format of the Guid. It's not easily read or formatted on a report. I wanted to find a way to represent very large integers such as the Guid (a 128 bit integer under the covers), so I looked around and found a Base 36 type sample on Code Project article by Steve Barker that gave me a great start.

The problem with Base 36 is that several characters are similar to other characters or numbers, so took the code and modified it to use a limited set of 20 characters that are distinctive from numbers and other characters sufficiently to make it easy for humans to read them back or hand enter them in a user interface.

I downloaded the code and went to work making the modifications. Here's the core of the Base 30 struct:

//removed are chars similar to numbers or another char when printed: I, J, O, Q, V, Z
private static List<char> alphaDigits = new List<char>(new char[]{ 'A','B','C','D','E','F','G','H','K','L','M','N','P','R','S','T','U','W','X','Y' });

private static byte Base30DigitToNumber(char Base30Digit)
{
    if(char.IsDigit(Base30Digit))
    {
        //Handles 0 - 9
        return byte.Parse(Base30Digit.ToString());
    }
    else
    {
        //Converts one base-30 digit to it's base-10 value
        if (alphaDigits.IndexOf(Base30Digit) > -1)
        {
            //Handles ABCDEFGHKLMNPRSTUWXY  (these are letters that cannot be confused for numbers)
            int index = alphaDigits.IndexOf(Base30Digit) + 10;
            return (byte)(index);
        }
        else
        {
            throw new InvalidBase30DigitException(Base30Digit);
        }
    }
}

private static char NumberToBase30Digit(byte NumericValue)
{
    //Converts a number to it's base-30 value.
    //Only works for numbers <= 29.
    if(NumericValue > 29)
    {
        throw new InvalidBase30DigitValueException(NumericValue);
    }

    //Numbers:
    if(NumericValue < 10)
    {
        return NumericValue.ToString()[0];
    }
    else
    {
        //Note that A is code 65, and in this
        //scheme, A = 10, Y = 29 ABCDEFGHKLMNPRSTUWXY  use alphaDigits for List<char>
        int index = NumericValue - 10;
        return alphaDigits[index]; //(char)(NumericValue + 55);
    }
}

Now, I have added a couple of static methods to give me a shiny Base 30 guid string and convert that string back to a Guid here:

/// <summary>
/// Convert a Guid to a set of four Base30 string values connected by a dash character.
/// </summary>
/// <param name="g"></param>
/// <returns></returns>
public static string GuidToBase30Set(Guid g)
{
    byte[] b = g.ToByteArray();
    Base30 b1 = BitConverter.ToUInt32(b, 0);
    Base30 b2 = BitConverter.ToUInt32(b, 4);
    Base30 b3 = BitConverter.ToUInt32(b, 8);
    Base30 b4 = BitConverter.ToUInt32(b, 12);
    return string.Format("{0}-{1}-{2}-{3}", b1, b2, b3, b4);
}

/// <summary>
/// Convert the Base30 set string produced by GuidToBase30Set back to a Guid.
/// </summary>
/// <param name="s"></param>
/// <returns></returns>
public static Guid Base30SetToGuid(string s)
{
    string[] p = s.Split('-');
    if (p.Length != 4) throw new ArgumentException("Invalid Base30Set format.");
    try
    {
        Base30 b1 = p[0];
        Base30 b2 = p[1];
        Base30 b3 = p[2];
        Base30 b4 = p[3];

        uint x1 = (uint)b1.NumericValue;
        uint x2 = (uint)b2.NumericValue;
        uint x3 = (uint)b3.NumericValue;
        uint x4 = (uint)b4.NumericValue;

        byte[] a1 = BitConverter.GetBytes(x1);
        byte[] a2 = BitConverter.GetBytes(x2);
        byte[] a3 = BitConverter.GetBytes(x3);
        byte[] a4 = BitConverter.GetBytes(x4);

        byte[] gb = new byte[16];

        a1.CopyTo(gb, 0);
        a2.CopyTo(gb, 4);
        a3.CopyTo(gb, 8);
        a4.CopyTo(gb, 12);

        return new Guid(gb);
    }
    catch
    {
        throw new ArgumentOutOfRangeException("Invalid Base30Set string.");
    }
}

The code above gets you something like this:

Common Guid string: b908d243-c1ac-4ea4-a954-121e4ab5c334
Base30Set from same: 47PGC95-1S8WCHP-MPTTA1-16CUN8P

You can download the code here (Base30.zip 3.6 KB).

ASP.NET MVC RedirectUrl on Login

In my first attempt at creating a real applicaiton using the new ASP.NET MVC project template (Codeplex Preview 5), I found that when I clicked a new tab I'd created linked to a specific controller and an action I'd decorated with the [Authorize(Roles = "user")] attribute, the "out of the box" Login action did not redirect me to the that controller/action combo once I had successfully logged in.

Here's my solution to the problem. First, I added a hidden value in the Login.aspx form. Second, I added a parameter to the Login action in the Acount controller (AccountController.cs). Let me know if you've found a better way.

Here's the code for the form:

<form method="post" action="<%= Html.AttributeEncode(Url.Action("Login")) %>">
    <div>
        <table>
            <tr>
                <td>
                    Username:
                </td>
                <td>
                    <%= Html.TextBox("username") %>
                </td>
            </tr>
            <tr>
                <td>
                    Password:
                </td>
                <td>
                    <%= Html.Password("password") %>
                </td>
            </tr>
            <tr>
                <td>
                </td>
                <td>
                    <input type="checkbox" name="rememberMe" value="true" />
                    Remember me?
                </td>
            </tr>
            <tr> <!-- Added to handle the returnUrl -->
                <td>
                    <%= Html.Hidden("returnUrl", ViewData["ReturnUrl"].ToString()) %>
                </td>
                <td>
                    <input type="submit" value="Login" />
                </td>
            </tr>
        </table>
    </div>
</form>

Here's the code for the Login action:

public ActionResult Login(string username, string password, bool? rememberMe, string returnUrl)
{
    ViewData["Title"] = "Login";
    string url = (string.IsNullOrEmpty(returnUrl) 
        ? Request.QueryString["ReturnUrl"] ?? string.Empty 
        : returnUrl)
        .Trim('/');
    ViewData["ReturnUrl"] = url;

    // Non-POST requests should just display the Login form 
    if (Request.HttpMethod != "POST")
    {
        return View();
    }

    // Basic parameter validation
    List<string> errors = new List<string>();

    if (String.IsNullOrEmpty(username))
    {
        errors.Add("You must specify a username.");
    }

    if (errors.Count == 0)
    {

        // Attempt to login
        bool loginSuccessful = Provider.ValidateUser(username, password);

        if (loginSuccessful)
        {
            FormsAuth.SetAuthCookie(username, rememberMe ?? false);
            if (url != null && url.Length > 0)
                return RedirectToAction("Index", url);
            else
                return RedirectToAction("Index", "Home");
        }
        else
        {
            errors.Add("The username or password provided is incorrect.");
        }
    }

    // If we got this far, something failed, redisplay form
    ViewData["errors"] = errors;
    ViewData["username"] = username;
    return View();
}