# Saturday, May 02, 2009

Here’s my favorite feature’s of Windows 7 release candidate right after install into a VMware virtual machine.

win7rc

posted on Saturday, May 02, 2009 3:20:01 PM (Mountain Daylight Time, UTC-06:00)  #    Comments [0]
# Monday, April 27, 2009

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();
        }
    }
}
posted on Monday, April 27, 2009 9:31:03 PM (Mountain Daylight Time, UTC-06:00)  #    Comments [8]
# Sunday, March 15, 2009

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);
    }
}
posted on Sunday, March 15, 2009 9:29:31 AM (Mountain Daylight Time, UTC-06:00)  #    Comments [0]
# Saturday, January 10, 2009

Every few months I give up on stacking everything on my desk and begin the arduous task of cleaning it up. In my most recent battle with desktop clutter, I came to realize that I am a book addict. Set aside the numerous entertaining novels I've bought and read over the last few months because they don't make it to my work desk. If they did, I'd never get any work done.

Here's a list of just the books currently floating in the stacks on my desk. No, I am not making this up. And no, I'm not going to give you a link to each one of them. You can always hit www.amazon.com or your favorite alternative and look them up. Many of these come from my local Borders store and others from Amazon. My Amazon Prime account has more than paid for itself.

I must also confess that some of these were not purchased recently but have somehow made their way back off my shelf and onto my desk in recent months. The order is of no particular import except to note that it is essentially a LIFO list which may provide a quasi reverse chronological order to my wandering interests and/or problems/challenges.

  • Agile Principles, Patterns and Practices in C# by Martin and Martin
  • The Data Model Resource Book Volume 1 by Silverston
  • The Data Model Resource Book Volume 2 by Silverston
  • The Data Model Resource Book Volume 3 by Silverston and Agnew
  • Pro ASP.NET 2.0 in C# 2005 by MacDonald and Szpuszla
  • SQL Server Analysis Services 2005 with MDX by Harrinath and Quinn
  • Windows Workflow Foundation by Scribner
  • Programming WCF Services by Lowy
  • Pro C# 2008 and the .NET 3.5 Platform by Troelsen
  • jQuery in Action by Bibeault and Katz
  • Building a Data Warehouse by Rainardi
  • Programming Collective Intelligence by Segaran
  • Workflow in the 2007 Microsoft Office System by Mann
  • Pro SharePoint 2007 Development Techniques by Bruggeman and Bruggeman
  • Regular Expressions by Friedl
  • Regular Expression Recipes for Windows Developers by Good
  • Microsoft SharePoint Buidling Office 2007 Solutions in C# 2005 by Hillier
  • C# Cookbook by Teilhet and Hilyard
  • Refactoring Databases Evolutionary Database Design by Ambler and Sadalage
  • SharePoint Server 2007 Best Practices by Curry and English

Update: Wandering through the house, I found several more at various favorite reading spots. They've now taken their proper place on my desk piles. Here they are:

  • Pro Silverlight 2 in C# 2008 by MacDonald
  • Thinking in C++ Second Edition Volume 1 by Eckel
  • Chris Crawford on Interactive Storytelling by Crawford
  • A Programmer's Introduction to C# Second Edition by Gunnerson
  • Visual C# 2005: The Base Class Library by Balena (I won this one)

Yes, this is a sad but not unhealthy addiction. The only detriment here is to my pocketbook and the fact that I'm running out of shelf space. Do you any of you have similar addictions?

posted on Saturday, January 10, 2009 12:12:24 PM (Mountain Standard Time, UTC-07:00)  #    Comments [1]
# Saturday, January 03, 2009

Yesterday's post dealt with Len Silverston's Party Role model and how to take it to a physical model using ER/Studio. After re-reading the post, I realized that while a party may have a role that distinguishes it as a person rather than an organization such as "Employee," a party might also have a role that is indistinguishable such as "Customer." So if I have a PARTY ROLE with a ROLE TYPE of "Customer," how do I know whether this customer is an individual or an organization if I have some business rule that must handle an order for one in a different way than the for the other?

The answer, I believe, is in adding a PARTY TYPE which tells me what "sub type" the party is but does not tell me what role the party may play in the system. This distinguishes a "type" from a "role" in that the party can only be one type but might play one or more roles in the system at the same time or at different times. Here's what I ended up with (see update 01/04/09 for corrected diagram):

rolepartytype

In this way, I can always determine through query what sub-type the party is regardless of the role. Of course, I could perhaps deal with this by having roles that uniquely apply to a specific sub-type but I think that would defeat the purpose of Len's model.

I'd like to hear what you think.

Update: Browsing Len's Volumne 1 on data modeling, I discovered that this is indeed covered in the Party Role model on page 440. And Karen is right about the relationship. I was too eager to post up the image and so overlooked the fact that I'd created the wrong type of relationship between the PARTY TYPE and PARTY entities in ER/Studio. I'll post up a fix soon.

Update 2 (01/04/09): Here's the corrected diagram with the non-identifying relationship. See Karen's comment.

rolepartytype1

Yeah, that looks better.

posted on Saturday, January 03, 2009 9:44:35 AM (Mountain Standard Time, UTC-07:00)  #    Comments [3]
# Friday, January 02, 2009

A central theme in my current work is the idea of a universal data model. Research in this direction led to noted author and consultant Len Silverston and his work on the subject which led to licensing ER/Studio and Len's models from Embarcadero. Soon after that, we invited Len to our offices to help us better understand his approach to data models and the process of data modeling. It was an informative and very productive three days. I wholeheartedly recommend his books and his consulting services to you. (See www.univdata.com.)

One of the most difficult concepts to grasp, for me at least, in the realm of data modeling is the transition from logical data model to physical database schema. When I look at boxes and lines with crow's feet connectors, I think of physical database tables. So looking at a logical model like this one makes me think of twelve tables.

model1  

The model depicted above (created using ER/Studio) is a simplification of Len's party role logical model that he talks about in his book Data Model Resource Book Volume 1. I've marked the entities that are "logical" and not physical in nature with a yellow background. ER/Studio allows me to mark these entities in the model as "logical" so that they will not be generated in the physical model that the modeling tool will create for you. The only problem is the PARTY ROLE TYPE entity, if marked as "logical," does not get generated and the relationship and foreign key does not get created in the PARTY ROLE table in the physical model.

When you add attributes such as those that PERSON and ORGANIZATION have that are unique to a sub-type, you have to push them to the physical model. Where the sub-type has no unique attributes but can be represented by a unique value record in the super-type entity/table, that entity can remain "logical only."

So now I modify the model and remove PARTY ROLE TYPE and create a relationship between ROLE TYPE and PARTY ROLE and then generate a physical model and this is what I get:

model2  

From the physical model I can generate a database script and create a database. Perhaps it is not practical to generate the physical model from the logical model in all cases, but where it can be done in order to avoid maintaining two separate models and risk synchronization issues, I would encourage it.

I'm looking forward to getting Len's next book that focuses on patterns in data modeling which ships next week. Amazon already has my order.

posted on Friday, January 02, 2009 4:31:33 PM (Mountain Standard Time, UTC-07:00)  #    Comments [2]
# Wednesday, December 31, 2008

I've recently been looking for simpler and more effective tools for collaborating with geographically distributed teams. The first order of business is to find something better than a whiteboard that can be shared amongst multiple users. After some brief searching, I found Dabbleboard at www.dabbleboard.com. This gem was just recently launched and I'm impressed. The image below was created using the free version of the tool online in just a few minutes. I highly recommend that you give it a try.

proto

The next order of business is to find a better way to prototype a business application that will allow us to define data and business logic in code and sharing that in a prototype that will allow users to interact with the business model without having to build a complex UI prototype and without having to map business objects to the database. While wandering around a site called InfoQ I found through Markin Fowler's blog, I ran into Naked Objects for .NET. I was dubious at first but spend some time watching the videos and wandering around the site. I like what see.

I'm just beginning to use these two tools in a real effort to determine whether they will really make my job and life easier. I am hopeful and impressed with what I've seen so far. The drawing I've created and included in this post illustrates how the Naked Objects technology might be used in what I'm building for my employer. I'm not sure if it represents exactly what will happen in the future but the guys at Dabbleboard have certainly made it easier to envision and to share with my colleagues no matter where they are.

posted on Wednesday, December 31, 2008 2:53:15 PM (Mountain Standard Time, UTC-07:00)  #    Comments [0]
# Thursday, December 11, 2008

After a long search for the right business process management platform that would allow us to integrate and extend with .NET, my team selected the Ultimus BPM Suite. The primary factors in the decision were the comprehensive nature of the solution which would allow us to deploy process management without requiring the use of some other tool such as InfoPath or SharePoint. Additionally, the solution would allow an incomplete process to be deployed and have assigned "process experts" make final decisions about business rules that may not have been clear or available at the time the process was designed.

I spent all of last week at their North Carolina offices in a "jumpstart" training course and met many of the key players at the company. Good people all around. Their technical expertise and willingness to listen to our team's concerns were impressive. There were a few minor UI glitches that we brought to their attention such as some scrolling issues when designing a process with limited screen real estate. The Ultimus people were genuinely interested in our input.

Having initially found and recommended the product, I was even more impressed with the product as we went through detailed training that brought out a number of features and illustrated an architecture that gave me even greater confidence in the product. This was particularly true in the area of integration points with existing systems and the ability to extend the process using custom developed controls or even process context aware ASP.NET pages hosted outside of the process server.

Our only disappointment was that some of the the training session content could have been improved as at times some of the class members were left a little lost and fell behind. This was in part because the "jumpstart" course was designed to fit a lot of material into a few days, but it was in part due to a lack of maturity in the content and presentation. We were very candid with the Ultimus training director about this and he took our input eagerly and promised improvement. Based on my conversations with key Ultimus employees, I believe that will happen.

If you are looking for a better way to deliver business process management and enterprise human-centric workflow solutions, you should consider Ultimus. There were other systems that were much more expensive that may have fit our requirements, but this was the only one we found that allowed us the freedom to extend and customize using our .NET dev skills without requiring coding skills to design and modify and manage processes.

I'll be writing more about Ultimus as our experience with the product continues.

posted on Thursday, December 11, 2008 8:37:43 AM (Mountain Standard Time, UTC-07:00)  #    Comments [0]
# Sunday, December 07, 2008

The following spam message (less the links) skipped through my spam filters somehow. If you are not a native speaker of English, this message may appear to be in order if your skill level with the language is limited. Otherwise, I suspect you will find this text as amusing as I did. I have not modified a single character. Enjoy...

welcome to order,
Our company is one of the largest wholesalers in Asia ,and we sell products to all over the world,we have the authorithed licence issured by Chinese government,all products in our company ranges from varieties of electronic products like mobilephone ,television, laptop,DVD,GPS,MP3/4 to photograph video game ,scanner, motorcycle prohector and so on..
We have earned our reputation in the world through our honesty business practice in the past years,and obtained many compliments from our clients globally.As we are the direct wholesalers for many reputable brands in the world,so all the products purchased in our website are promised to be at a lower price with the high quality,also all the facuty products will be returned within 7 days,exchange within 14 days,repair within 2 years without charge.
We will be right here waiting for your visitation.

I hope that as software architects and engineers we are producing code and other textual artifacts that communicate with greater clarity and understanding of the language and idiom in which we express our ideas. Do we write documentation as badly because we can only communicate clearly in code? Or vice versa? It is something to think about.

posted on Sunday, December 07, 2008 11:19:36 AM (Mountain Standard Time, UTC-07:00)  #    Comments [0]
# Monday, November 24, 2008

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).

posted on Monday, November 24, 2008 5:27:19 PM (Mountain Standard Time, UTC-07:00)  #    Comments [0]