Josh Heyse

Thoughts Defragmented

Archive for April, 2008

Community Server 2.1 SP3 Blog Attachment Quota Error

Posted by jheyse on 16th April 2008

I’ve been blogging more recently and I have started including images and attachments to my blogs thanks to the ease provided by Windows Live Writer. I have been using this feature more than the others bloggers at Catalyst so I was the first to run into an issue.  Community Server enforces quotas on the attachments uploaded using the metablog.ashx handler.  It was a little hard to come by this information though. Windows Live Writer was reporting the following error:

LiveWriterError

"The following images cannot be published because the weblog does not support image publishing."

My next step was to open up Fiddler2 to investigate the error message being sent back by the metablog handler.  The error was pretty vague with the error message "Invalid File".  I started to search the web for help, but couldn’t find anything. 

 

 

I was having trouble finding error messages reported by Community Server.  It took me a while to find the error log in Community Server under the control panel. There I found a message that described a little more detail and gave me something to go on:

An error occurred while uploading a file via MetaWeblogAPI NewMediaObject.

CommunityServer.Components.CSException
Your post has been saved, but the attachment was not.<P>Your attachment exceeded the forums maximum size limit of The size of this blog file would cause the blog to exceed the maximum total file size.KB.

From here I searched and found several references to a feature in the Community Server Control Panel called "Blog File Storage Settings" which I could not find. I believe this is a feature only provided within Community Server 2007 and greater.  So I kept digging, eventually I broke down and remoted to the machine and started looking through the web project. Something where I should have started in the first place.  I checked the metablog.ashx file and suprisingly enough the source code was right there.  From that point the solution was easy.  In the code I found references to two configuration settings stored in the appSettings section.  I added these and we were back in business.

Posted in Community Server, Live Writer | No Comments »

Multi-linking projects between Silverlight and the Desktop CLR

Posted by jheyse on 14th April 2008

I’ve started digging into Silverlight pretty heavily over the past couple of weeks.  My main interest is in developing Line of Business applications using Silverlight.  I am desperately trying to move beyond HTML, Javascript, and the stateless nature of current web development.  I’ve become fond of WinForms development and even more interested in WPF development, data binding is our friend.

SilverlightReference

One of the main benefits I, and others, have been preaching about Silverlight is the ability to write the same code for both the desktop and the ‘web’ using Silverlight.  Well this is only partially true, the language is identical; the referenced and complied assembly are not.  This is obvious when trying to reference a Silverlight project from a Desktop CLR project.  You will receive the following error: "Silverlight projects can only be referenced by other Silverlight projects".

Now I am a pretty stubborn person, and this just wasn’t acceptable. So I started digging into the matter.  The issue really is nothing more the the IDE saying no. As long as you are only referencing assemblies and using types & methods that exist in both the Silverlight and Desktop frameworks there is no reason this shouldn’t work.  So I started to Live Search… whom I’m kidding I Goggled the issue.  I found a post by Paul Stovell describing how to manually compile a Desktop CLR assembly for use in Silverlight apps.  This was enough to get me started with a few minor tweaks:

1) I believe that it is safer to create a Silverlight Class Library for shared components and references that in your Silverlight and Desktop CLR applications.  The reason for this is that the Silverlight Framework is a subset of the Desktop CLR and it’s very easy to include types & methods which are not part of the Silverlight Framework. 

2) Pre & Post build scripts just don’t cut it for me anymore.  They aren’t dynamic enough, so enter MSBuild. 

So with these two modifications, I tackled the problem. I have created two MSBuild targets files which will compile the Silverlight project against the Desktop CLR.  One is for CSharp, and the other VisualBasic.  I will walk through the CSharp.targets build file as an example. If you would like to read more on MSBuild, I recommend this article by Sayed Hashimi.

The first part of the MSBuild file appends my Build step to the Build order defined within Microsoft.Common.Targets.  I found this tip on the MSBuild blog site.

<PropertyGroup>
  <BuildDependsOn>
    $(BuildDependsOn);
    CompileForFramework
  </BuildDependsOn>
</PropertyGroup>

The next step was to define a custom target to recompile against the DesktopCLR.  I had to modify the Inputs and Outputs so that the Target would run, I did this by moving the IntermediateAssembly form the outputs to the inputs. The decoration for the target looks like this"

<Target Name="CompileForDesktopCLR"
        Inputs="$(MSBuildAllProjects);
              @(Compile);                               
              @(_CoreCompileResourceInputs);
              $(ApplicationIcon);
              $(AssemblyOriginatorKeyFile);
              @(ReferencePath);
              @(CompiledLicenseFile);
              @(EmbeddedDocumentation); 
              $(Win32Resource);
              $(Win32Manifest);
              @(IntermediateAssembly);
              @(CustomAdditionalCompileInputs)"
      Outputs="@(DocFileItem);
               @(_DebugSymbolsIntermediatePath);                
               $(NonExistentFile);
               @(CustomAdditionalCompileOutputs)"
      DependsOnTargets="$(CompileForDesktopCLRDependsOn)">

Next I added a task to create a /bin directory in the shared assembly project.  By default Silverlight Class Libraries get build to the /ClientBin directory. This is accomplished by the following task:

<MakeDir Condition="!Exists(bin)" Directories="bin" />

The last step is to modify the task which calls to the compiler.  Based on Paul’s post the only compiler parameter differences that matter are the referenced dlls and the output path.  I transformed the output assembly and references using the following code:

<Csc  Condition=" '%(_CoreCompileResourceInputs.WithCulture)' != 'true' "
      ...
      OutputAssembly="@(IntermediateAssembly->'bin%(FileName)%(Extension)')"
      ...
      References="@(ReferencePath->'%(FileName)%(Extension)')" />

I have attached the two MSBuild files below.  To uses these files, copy them to your MSBuild/Silverlight directory.  On most machines this will be located at C:Program FilesMSBuildSilverlight2.0.  Next open your solution with the Silverlight Class Library you would like to share.  Right-click the class library and select unload project, then right-click again and select Edit.  Change the line:

<Import Project="$(MSBuildExtensionsPath)MicrosoftSilverlightv2.0Microsoft.Silverlight.CSharp.targets" />

to

<Import Project="$(MSBuildExtensionsPath)MicrosoftSilverlightv2.0Catalyst.Silverlight.CSharp.targets" />

Right-click on your class library again and select Reload Project.  If the csproj file is still open in edit mode you will be prompted to close it, select Yes. Next you will be show a Security Warning that states that the project has been customized and could present a security risk.  Select Load project normally, you will be prompted with this warning everytime you open the solution unless you add the path of the targets file to the registry. Here is an excerpt from the MSDN site:

Non-standard Import Elements

A list of standard .targets files is stored in the registry at HKEY_LOCALMACHINESoftwareMicrosoftVisualStudio8.0MSBuildSafeImports. If a project file imports a .targets file that is not stored in the registry, it is determined to be a potential security risk.

Posted in .NET, Silverlight | 1 Comment »

A Richer DynamicFilterRepeater – Updated for April Release

Posted by jheyse on 11th April 2008

This week the Dynamic Data team has released a new drop of the runtime and templates.  It is substantially different and they have made many improvements to the design.  These changes, as expected, broke a significant portion of the Dynamic Filter controls I have been working on.  Last night I dug into the new bits and was able to breath life back into the dynamic filtering. 

Once I had finished doing symbolic renames on many of the properties and types renamed from the Decmeber CTP, I ran into several issues with the reflection based code I have written to inject the advanced querying capabilities into the existing controls.  I am going to start documenting what I have had to ‘hack’ to make the dynamic querying work.  Hopefully I can work with team members within Microsoft to promote some of the methods and types to the public. 

Here are some screen shots of the new implementation:

DD_4

DD_5

Download Solution: DynamicData.zip

Posted in .NET, ASP.NET, C#, Dynamic Data, LINQ | 1 Comment »

A Richer DynamicFilterRepeater – Part 4 Custom DynamicFilterControls & Expressions

Posted by jheyse on 11th April 2008

In post 2 in this series I contrived a scenario where composite parameters were used to select products from the AdventureWorks database by weight.  The weight of products is stored in either lbs or grams which make it necessary for the following SQL logic:

select
    *
from
    Production.Product
where
    (WeightUnitMeasureCode = 'LB' and Weight >= 2 and Weight <= 3) or
    (WeightUnitMeasureCode = 'G' and Weight >= 907 and Weight <= 1306)

Previously, this was accomplished by compounding a serious of And, Or, and Range expressions together.  We can condense this down to a single custom range parameter and corresponding FilterUserControl.

The first step is to create a user control which extends RangeFilterUserControlBase.  We will name it Weight and place it in the ~/App_Shared/DynamicDataFilters/ folder.  The control will allow for values in both Grams and Pounds to support globalization, so we need to add a UnitType property.  The ascx for the control defines tbMin, tbMax, and a DropDownList to allow the user to select either Pounds or Grams.  The control extends RangeFilterUserControlBase and overrides the default implementation of GetWhereParameters and returns a WeightExpressionParameter which we will define next.

public partial class Weight : Catalyst.Web.DynamicData.RangeFilterUserControlBase
{
    public enum WeightUnit
    {
        Pounds,
        Grams
    }

    public WeightUnit UnitType
    {
        get
        {
            return (WeightUnit)Enum.Parse(typeof(WeightUnit), DropDownList1.SelectedValue);
        }
        set
        {
            DropDownList1.Items.FindByValue(value.ToString()).Selected = true;
        }
    }

    public override string MinValue
    {
        get
        {
            return tbMin.Text;
        }
        set
        {
            tbMin.Text = value;
        }
    }

    public override string MaxValue
    {
        get
        {
            return tbMax.Text;
        }
        set
        {
            tbMax.Text = value;
        }
    }

    public override TypeCode Type
    {
        get { return TypeCode.Decimal; }
    }

    public override IEnumerable<Parameter> GetWhereParameters(IDynamicDataSource dataSource)
    {
        yield return new WeightExpressionParameter()
        {
            Name = this.DataField,
            MinValue = this.MinValue,
            MaxValue = this.MaxValue,
            UnitType = this.UnitType,
            Type = this.Type
        };
    }
}

The WeightExpressionParameter extends the RangeExpressionParameter and overrides the GetLambaExpression to return a LambdaExpression which will do the Grams to Pounds conversion for us.  The WeightExpressionParameter also includes a property for the UnitType which is stored in ViewState to ensure post backs and Ajax enabled controls work correctly.

public class WeightExpressionParameter : RangeExpressionParameter
{
    private const decimal ConversionFactor = 453.59237m;

    public WeightUnit UnitType
    {
        get
        {
            object obj2 = this.ViewState["UnitType"];
            if (obj2 == null)
            {
                return WeightUnit.Pounds;
            }
            return (WeightUnit)obj2;
        }
        set
        {
            if (this.UnitType != value)
            {
                this.ViewState["UnitType"] = value;
                this.OnParameterChanged();
            }
        }
    }

    public override LambdaExpression GetLambdaExpression(Type itType)
    {
        decimal? min = (decimal?)MinParameterValue;
        decimal? max = (decimal?)MaxParameterValue;

        if (UnitType == WeightUnit.Grams)
        {
            min /= ConversionFactor;
            max /= ConversionFactor;
        }

        if(itType == typeof(BusinessObjects.Product))
        {
            Expression<Func<BusinessObjects.Product, bool>> x = p =>
                (min == null || (p.WeightUnitMeasureCode == "lb" ? p.Weight : p.Weight / ConversionFactor) >= min) &&
                (max == null || (p.WeightUnitMeasureCode == "lb" ? p.Weight : p.Weight / ConversionFactor) <= max);
            return x;
        }
        else
            throw new ArgumentException("Expected itType to be of type BusinessObjects.Product", "itType");
    }
}

The LINQ-to-SQL interpreter is amazingly smart and is able to understand fairly complex statements. This SQL that is passed to the database server is exactly what we are looking for, it is even able to short circuit the query if either min or max is null!

SELECT TOP (10) [t0].[ProductID], [t0].[Name], [t0].[ProductNumber], [t0].[MakeFlag], [t0].[FinishedGoodsFlag], [t0].[Color], [t0].[SafetyStockLevel], [t0].[ReorderPoint], [t0].[StandardCost], [t0].[ListPrice], [t0].[Size], [t0].[SizeUnitMeasureCode], [t0].[WeightUnitMeasureCode], [t0].[Weight], [t0].[DaysToManufacture], [t0].[ProductLine], [t0].[Class], [t0].[Style], [t0].[ProductSubcategoryID], [t0].[ProductModelID], [t0].[SellStartDate], [t0].[SellEndDate], [t0].[DiscontinuedDate], [t0].[rowguid], [t0].[ModifiedDate], [t2].[test], [t2].[ProductSubcategoryID] AS [ProductSubcategoryID2], [t2].[ProductCategoryID], [t2].[Name] AS [Name2], [t2].[rowguid] AS [rowguid2], [t2].[ModifiedDate] AS [ModifiedDate2], [t4].[test] AS [test2], [t4].[ProductModelID] AS [ProductModelID2], [t4].[Name] AS [Name3], [t4].[CatalogDescription], [t4].[Instructions], [t4].[rowguid] AS [rowguid3], [t4].[ModifiedDate] AS [ModifiedDate3]
FROM [Production].[Product] AS [t0]
LEFT OUTER JOIN (
    SELECT 1 AS [test], [t1].[ProductSubcategoryID], [t1].[ProductCategoryID], [t1].[Name], [t1].[rowguid], [t1].[ModifiedDate]
    FROM [Production].[ProductSubcategory] AS [t1]
    ) AS [t2] ON [t2].[ProductSubcategoryID] = [t0].[ProductSubcategoryID]
LEFT OUTER JOIN (
    SELECT 1 AS [test], [t3].[ProductModelID], [t3].[Name], [t3].[CatalogDescription], [t3].[Instructions], [t3].[rowguid], [t3].[ModifiedDate]
    FROM [Production].[ProductModel] AS [t3]
    ) AS [t4] ON [t4].[ProductModelID] = [t0].[ProductModelID]
WHERE ((
    (CASE
        WHEN [t0].[WeightUnitMeasureCode] = @p0 THEN CONVERT(Decimal(29,5),[t0].[Weight])
        ELSE [t0].[Weight] / @p1
    END)) >= @p2) AND ((
    (CASE
        WHEN [t0].[WeightUnitMeasureCode] = @p3 THEN CONVERT(Decimal(29,5),[t0].[Weight])
        ELSE [t0].[Weight] / @p4
    END)) <= @p5)
-- @p0: Input NVarChar (Size = 2; Prec = 0; Scale = 0) [lb]
-- @p1: Input Decimal (Size = 0; Prec = 29; Scale = 5) [453.59237]
-- @p2: Input Decimal (Size = 0; Prec = 34; Scale = 5) [2]
-- @p3: Input NVarChar (Size = 2; Prec = 0; Scale = 0) [lb]
-- @p4: Input Decimal (Size = 0; Prec = 29; Scale = 5) [453.59237]
-- @p5: Input Decimal (Size = 0; Prec = 34; Scale = 5) [3]
-- Context: SqlProvider(Sql2005) Model: AttributedMetaModel Build: 3.5.21022.8

Here is a screen shot of the control in action:

WeightFilterControl

Weight Filter Control Example: Weight.zip

Posted in .NET, ASP.NET, C#, Dynamic Data, LINQ | No Comments »

A Richer DynamicFilterRepeater – Part 3 DynamicFilterControl

Posted by jheyse on 10th April 2008

In part 1 of this series I discussed extending the LinqDataSource to provided advanced querying capabilities using the System.Linq.Dynamic namespace.  Part 2 demonstrated creating advanced WhereParameters which allowed for for complex binary logic.  In this posting I am going to go through our first ASP.NET Web Control which brings this powerful functionality to the user.

My original intention of this blog series was to create a more powerful DynamicFilterControl to replace the one currently in the Dynamic Data portion of the ASP.NET 3.5  Extensions.  During a recent project where we use the Dynamic Data framework, it became apparent that the repeater limited our layout ability and a DynamicFilterForm was better suited.  I choose the name DynamicFilterForm to follow the naming convention of the ASP.NET databound controls.

So, let’s start off with a demo of the the DynamicFilterForm.  In this demo I am building on the Products  example used in previous postings.  For the List.aspx page we’d like to be able to filter on the fields displayed in the DataGrid.

DynamicFilterForm_1[5]

The search allows for all of the fields, except weight, to be search on.  The Name, Product Number, Class and Color allow for partial string matches, ListPrice allows for a range, Subcategory uses a single selection drop down which is populated through the ForiegnKey, and Product Model allows for multiple selection.

The DynamicFilterForm allows for 3 commands: Search, Clear, and Browse.  (More on these later).

Let’s take a look at the ASP.NET code that runs the form:

<cc1:DynamicFilterForm DataSourceID="GridDataSource" runat="Server" ID="DynamicFilterForm1">
    <FilterTemplate>
        <div>
            Search
        </div>
        <table>
            <tr>
                <td>
                    Name:
                </td>
                <td>
                    <cc1:DynamicFilterControl ID="DynamicFilterControl3" runat="server" DataField="Name"
                        FilterMode="Contains" />
                </td>
                <td>
                    Product Number:
                </td>
                <td>
                    <cc1:DynamicFilterControl ID="DynamicFilterControl5" runat="server" DataField="ProductNumber"
                        FilterMode="Contains" />
                </td>
                <td>
                    Class:
                </td>
                <td>
                    <cc1:DynamicFilterControl ID="DynamicFilterControl6" runat="server" DataField="Class"
                        FilterMode="Contains" />
                </td>
                <td rowspan="2" valign="top">
                    Product Model:
                </td>
                <td rowspan="2" valign="top">
                    <cc1:DynamicFilterControl ID="DynamicFilterControl7" runat="server" DataField="ProductModel" FilterMode="MultiSelect" />
                </td>
                <td rowspan="2" valign="top">
                    <asp:LinkButton runat="server" CommandName="Search">Search</asp:LinkButton><br />
                    <asp:LinkButton runat="server" CommandName="Clear">Clear</asp:LinkButton><br />
                    <asp:LinkButton runat="server" CommandName="Browse">Browse</asp:LinkButton>
                </td>
            </tr>
            <tr>
                <td>
                    List Price:
                </td>
                <td>
                    <cc1:DynamicFilterControl ID="DynamicFilterControl1" runat="server" DataField="ListPrice"
                        FilterMode="Range" />
                </td>
                <td>
                    Color:
                </td>
                <td>
                    <cc1:DynamicFilterControl ID="DynamicFilterControl4" runat="server" DataField="Color"
                        FilterMode="Contains" />
                </td>
                <td>
                    Subcategory:
                </td>
                <td>
                    <cc1:DynamicFilterControl ID="DynamicFilterControl2" runat="server" DataField="ProductSubcategory" />
                </td>
            </tr>
        </table>
    </FilterTemplate>
</cc1:DynamicFilterForm>

DynamicFiltersFolder

The DynamicFilterForm mimics the functionality of the other DynamicData controls.  The DynamicFilterForm is a container object which has a FilterTemplate template that defines the layout.  Inside the FilterTemplate you define DynamicFilterControls.  These controls are responsible for loading the correct user control from the ~/App_Shared/DynamicDataFilters/ folder.  Here you can see I have created filter controls for each of the field types declared in the DynamicDataFields folder which are included in the base solution.

The DynamicFilterControl has a property FilterMode which allows for the following different enumeration values: Equals, Contains, Range, Multiselect.  This mode is appended to the field type like the DynamicControls.  So if you want to allow for a range of integers, the control name would be Integer_Range.ascx.  To facilitate quicker development and code reuse each of the custom DynamicExpressionParameters (EqualsExpressionParameter, InExpressionParameter, etc…) has a corresponding FilterTemplateUserControlBase(EqualsFilterUserControlBase, InFilterControlUserBase, etc…).

Here are the abstract methods for the FilterTemplateUserControlBase which need to be implemented.

public abstract class FilterTemplateUserControlBase : FieldTemplateUserControlBase, IWhereParametersProvider
{
    public abstract IEnumerable<Parameter> GetWhereParameters(IDynamicDataSource dataSource);
    public abstract void LoadQueryStringParameters(NameValueCollection parameters);
    public abstract NameValueCollection SaveQueryStringParameters();
    public abstract void Clear();

}

GetWhereParameters is the meat of this class, it is what is responsible for instantiating and returning the ExpressionParameter which is added to the DynamicLinqDataSource control’s where parameters.  Don’t you love the separation of concerns? I DO! The Clear method is called by the parent DynamicFilterForm when the Clear command is issued, this clears all values and researches to bring back the unfiltered result set.  LoadQueryStringParameters and SaveQueryStringParameters allow for the filter criteria to be stored in a URL.

<rant> One of my biggest annoyances on the web is developers who store state in session or form variables around searching.  Web users expect to be able to copy the URL of the page they are on and send it to their friend so that they can see the same thing. I run into this every time my friends and I are trying to plan a trip someplace and we are using Orbitz, Travelocity, etc… </rant>

Here is an example of the RangeFilterUserControlBase and the Integer_Range.ascx.cs control which extends it.

public abstract class RangeFilterUserControlBase : FilterTemplateUserControlBase
{
    public abstract string MinValue { get; set; }
    public abstract string MaxValue { get; set; }
    public abstract TypeCode Type { get; }

    public override IEnumerable<Parameter> GetWhereParameters(IDynamicDataSource dataSource)
    {
        yield return new RangeExpressionParameter() { Name = DataField, MinValue = MinValue, MaxValue = MaxValue, Type = Type };
    }

    public override void LoadQueryStringParameters(NameValueCollection parameters)
    {
        MinValue = parameters[string.Format("{0}_Min", DataField)];
        MaxValue = parameters[string.Format("{0}_Max", DataField)];
    }

    public override NameValueCollection SaveQueryStringParameters()
    {
        NameValueCollection parameters = new NameValueCollection();
        parameters.Add(string.Format("{0}_Min", DataField), MinValue);
        parameters.Add(string.Format("{0}_Max", DataField), MaxValue);
        return parameters;
    }

    public override void Clear()
    {
        MinValue = string.Empty;
        MaxValue = string.Empty;
    }
}

The Integer_Range.ascx control has two TextBoxes named tbMin and tbMax.

public partial class Integer_Range : Catalyst.Web.DynamicData.RangeFilterUserControlBase
{
    public override string MinValue
    {
        get
        {
            return tbMin.Text;
        }
        set
        {
            tbMin.Text = value;
        }
    }

    public override string MaxValue
    {
        get
        {
            return tbMax.Text;
        }
        set
        {
            tbMax.Text = value;
        }
    }

    public override TypeCode Type
    {
        get { return this.MetaMember.TypeCode; }
    }
}

As always, below is the source to the solution so far.  In my next post I will demonstrate creating your own FilterUserControl by re-implementing filtering on the Weight column.

Download Solution: DynamicData.zip

Posted in .NET, ASP.NET, C#, Dynamic Data, LINQ | No Comments »

Updated ASP.NET Dynamic Data Drop

Posted by jheyse on 10th April 2008

Scott Guthrie just posted about an updated version of the ASP.NET Dynamic Data framework.  I am going to look into this and investigate if there were any breaking changes to the Dynamic Filter control set.  I’m guessing there will be several since I am being a bad kid and using reflection to call non-public methods. LOL

Posted in .NET, ASP.NET, C#, Dynamic Data, LINQ | No Comments »

Windows Server 2008 Workstation

Posted by admin on 6th April 2008

Over the last couple of weeks my Vista SP1 installation started to degrade.  One of the wonders of the Windows operating system is how they all seem to slow down after 2 or 3 months of usage.  I’ve made it a habit to re-image my machine once a quarter, removing any unused applications and installing the new toys that I have found over the last couple months.  But this time instead of re-imaging Vista I started fresh with a copy of Windows Server 2008.

Several weeks ago I gave a presentation on Windows Server 2008 focusing on Hyper-V and IIS7, for the International Association of Microsoft Certified Partners (IAMCP).  I installed Windows Server 2008 on a Dell Vostro for the presentation.  It was around the time that I read this blog on running Windows Server 2008 as a workstation over Vista, so I configured the installation as a workstation and loved it.  The machine had all of the benefits of Vista like glass and the advanced start menu, but didn’t seem to run nearly as slowly.  This blog claims that there is a 11-17% performance increase by running Windows Server 2008 over Vista, they speculate that it is due to the removal of the DRM bloat added to Vista.

During this installation I ran into some minor difficulties, I am going to outline the issues and resolutions I encountered hopefully this will help anyone who runs across the same problems.

Machine Configuration

  • Dell Inspiron 9400
  • Core 2 Duo T5600 @ 1.83 Ghz
  • 2 GB Memory
  • ATI Mobility Radeon 1400
  • Windows Server 2008 x86

Video Drivers

Installing the default 32bit Vista ATI Drivers from the Dell web site, resulted in a lower resolution then I was hoping for.  The drivers only supported 1920 X 1080 instead of my monitor’s native 1920 x 1200.  To fix this I installed the latest version of the ATI Catalyst Driver Pack and the Mobility Modder both provided at Driverheaven.net.

Vista Experience

Next, I followed the instructions on the following two sites to convert my Windows Server 2008 install into the ultimate Vista machine.   Both sites cover a majority of the same topics but, win2008workstation.com looks like it will be an ongoing project.

Windows Live Writer

Once my machine was configured I set out to write this blog and thought I had hit a potential show stopper. After downloading Live Writer, I tried to run WLInstaller.exe and encountered an error that said Windows Server was unsupported.  I’ve become addicted to LiveWriter and can’t imagine going back to blogging using a WSYWIG HTML editor on a web app.  After some intensive googling, I found this article on a workaround.

 Workstation2008

After two days of usage, I am extremely happy with my new configuration.  There was roughly an additional hour of configuration to get my machine running but it was worth it.  I wonder if the guys at vLite, would be able to create a slip stream installation for Windows 2008 Workstation?

Posted in Live Writer, Windows Server 2008 | No Comments »

A Richer DynamicFilterRepeater: Part 2 – Advanced Parameters

Posted by admin on 5th April 2008

After extending the LinqDataSource in Part 1, I was curious to see what other types of parameters I could make.  My first idea was to create composite parameters for and/or operations.  The existing implementation of the LinqDataSource only allows you to append filter criteria to the list, which creates an AndAlso functionality.

Continuing with the AdventureWorks Products example, I devised a scenario where composite parameters would be useful. The Products in the AdventureWorks database allow you to store the weight of the item in either lbs or grams. This requires the use of a composite parameter to select all products which fall in between 2 – 3 lbs or the equivalent 907 – 1360 grams.  Since I have been playing with WPF and Silverlight I have taken a liking to the declarative syntax. The following query looked like this in my head:

<cc1:DynamicLinqDataSource ID="GridDataSource" runat="server">
    <WhereParameters>
        <cc1:OrExpressionParameter>
            <Parameters>
                <cc1:AndExpressionParameter>
                    <Parameters>
                        <cc1:EqualsExpressionParameter Name="WeightUnitMeasureCode" Value="LB" />
                        <cc1:RangeExpressionParameter Name="Weight" MinValue="2" MaxValue="3" Type="Int32" />
                    </Parameters>
                </cc1:AndExpressionParameter>
                <cc1:AndExpressionParameter>
                    <Parameters>
                        <cc1:EqualsExpressionParameter Name="WeightUnitMeasureCode" Value="G" />
                        <cc1:RangeExpressionParameter Name="Weight" MinValue="907" MaxValue="1360" Type="Int32" />
                    </Parameters>
                </cc1:AndExpressionParameter>
            </Parameters>
        </cc1:OrExpressionParameter>
    </WhereParameters>
</cc1:DynamicLinqDataSource>

Once I had the use case for the feature completed it was time to refactor my code to support the new functionality.  As I am writing this I am kicking myself for not creating some corresponding UnitTests for this little project.  If I have some time I will write up some tests before I release the code base to the public.

Anyway… To support the change in functionality I had to make several changes:

  • Modify IDyanmicExpressionParameter
  • Extend ParameterCollection
  • Create CompositeExpressionParameterBase

First, I had to modify the IDynamicExpressionParameter interface to support an additional method called GetLambdaExpression.  The reason for this is that we can’t just append to the query anymore, the composite parameters must compile their own binary tree of Lambda Expressions to work correctly.

public interface IDynamicExpressionParameter
{
    IQueryable AppendQuery(IQueryable query);

    LambdaExpression GetLambdaExpression(Type itType);
}

Next, I needed to extend the ParameterCollection to accept parameters beyond the built in ones with the .NET Framework.  Under my previous implementation parameters were not being tracked in ViewState and this was causing an issue with postbacks.  The DynamicParameterCollection accepts additional Parameter types, but still uses a hard coded list.  A better implementation would be to create a static list of knownTypes that appends new knownTypes as they are found.

public class DynamicParameterCollection : ParameterCollection
{
    private readonly Type[] _knownTypes = new Type[] { typeof(AndExpressionParameter),
                                                        typeof(OrExpressionParameter),
                                                        typeof(InExpressionParameter),
                                                        typeof(LikeExpressionParameter),
                                                        typeof(RangeExpressionParameter),
                                                        typeof(EqualsExpressionParameter) };

    protected override object CreateKnownType(int index)
    {
        int baseTypesLength = base.GetKnownTypes().Length;
        if(index < baseTypesLength)
            return base.CreateKnownType(index);

        return Activator.CreateInstance(_knownTypes[index - baseTypesLength]);
    }

    protected override Type[] GetKnownTypes()
    {
        List<Type> knownTypes = new List<Type>(base.GetKnownTypes());
        knownTypes.AddRange(_knownTypes);
        return knownTypes.ToArray();
    }
}

Lastly, I implemented CompositeExpressionParameterBase which supports both And and Or binary tree operations.  There were two key pieces to this class.

The first was wiring up the IStateManager interface to work properly with the parent DynamicParamterCollection.  This proved fairly difficult to debug before I remembered that I could now step into the .NET Framework using Visual Studio 2008. This was my first experience doing so, and I think it is a HUGE feature. The VS team rocks!

The next step was to implement binary trees as Lambda Expressions.  This forced me to get a little deeper into Lamdba Expressions and the ExpressionTreeVisualizer example paid off big time.  You can find the Debug Visualizer in the %PROGRAM FILES%Microsoft Visual Studio 9.0Samples1033CSharpSamples.zip directory.

LinqExpressionVisualizer

The code for creating a binary tree expression looks likes this:

protected LambdaExpression GetLambdaExpression(Type itType, ExpressionType binaryType)
{
    List<LambdaExpression> lambdas = new List<LambdaExpression>();
    foreach (Parameter p in Parameters)
    {
        LambdaExpression lambda = p.GetLambdaExpression(itType);
        if (lambda != null)
            lambdas.Add(lambda);
    }

    if (lambdas.Count == 0)
        return null;

    if (lambdas.Count == 1)
        return lambdas[0];

    LambdaExpression left = lambdas[0];
    LambdaExpression right = lambdas[1];

    ParameterExpression param = Expression.Parameter(left.Parameters[0].Type, "");
    BinaryExpression root = Expression.MakeBinary(binaryType, left.Body, right.Body);
    for (int i = 2; i < lambdas.Count; i++)
    {
        right = lambdas[i];
        root = Expression.MakeBinary(binaryType, root, right.Body);
    }

    left = Expression.Lambda(ReplaceParameter(root, param), param);
    return left;
}

Some other ideas for advanced parameters include a NotNullOrEmpty parameter and a Not parameter which inverses the result of the composite expression.  Up next I will talk about a writing web controls to expose this advance functionality to users.

Download Solution DynamicData.zip

Posted in .NET, ASP.NET, C#, Dynamic Data, LINQ | 1 Comment »

Indy Code Camp 2008

Posted by admin on 1st April 2008

I am presenting at the Indy Code Camp on April 26th, 2008.  I am pretty excited about the opportunity to begin speaking on .NET topics.  Community involvement is something I have wanted to do for a while, and I am finally in a position where I believe I have some thing to bring to the table and the time to do so.  Catalyst has been supporting my community involvement and it has become one of my responsibilities as a Senior Solution Architect.

The Indy Code Camp is being hosted by Aaron Lerch, who has a great blog at http://weblogs.asp.net/aaronlerch/default.aspx.

Location

The Gene B. Glick Junior Achievement
Education Center
7435 North Keystone Ave
Indianapolis, IN 46240

Date & Time:

Saturday, April 26, 2008
8:30 AM – 5:30 PM

Map image

[Woohoo: I got to use the LiveWriter Insert Map Plugin...]

Registration is free: http://www.indycodecamp.org/Register/tabid/424/Default.aspx

My Topics

Core: An Aspect Oriented Business Objects Framework
Learn about aspect-oriented design patterns and how they can be used to quickly add common functionality to your business objects. Aspect-oriented programming allows for the separation of true business logic and the code written allowing interaction with user interfaces. The Core framework is a generation model that dynamically adds common services, such as logging, auditing, persistence, and security to business objects. Aspects, or behaviors, are requested using attributes or configuration files which allows services to be included only where necessary eliminating overly bloated objects and tailored for the environment into which the object is loaded.

Line of Business Applications in Silverlight 2.0
Learn about Silverlight 2.0 and how it can be used to rapidly create feature rich line of business applications. Most Silverlight demos focus on the visual features and pass over binding and data manipulation. While, most developers do not create applications with animations and richly designed user interfaces, Silverlight is still a viable option for line of business application development. Learn how and why Silverlight 2.0 will change the way you write code while walking through the development of a simple CRM solution.

I am looking forward to this event, and hope that you can make it.  If not all presentation materials will be made available on my blog and the Indy Code Camp website.

Posted in Silverlight, Speaking | No Comments »