Databinding Nested Repeaters

Many of you might already know about this, but I’ll post it for those of you like me who didn’t. Occasionally I’ll nest a repeater inside of another repeater, and when I do I always attach an ItemDataBound event handler to the parent repeater so I can set the DataSource of the child repeater.

<asp:Repeater ID="rptManufacturers" runat="server" OnItemDataBound="rptManufacturers_ItemDataBound">
    <ItemTemplate>
        <%# Eval("Name") %>
        <asp:Repeater runat="server" ID="rptModels">
            <HeaderTemplate>
                <ul>
            </HeaderTemplate>
            <ItemTemplate>
                <li><%# Eval("ModelName") %></li>
            </ItemTemplate>
            <FooterTemplate>
                </ul>
            </FooterTemplate>
        </asp:Repeater>
    </ItemTemplate>
</asp:Repeater>
protected void rptManufacturers_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
        Manufacturer man = (Manufacturer)e.Item.DataItem;
        Repeater rptModels = (Repeater)e.Item.FindControl("rptModels");
 
        rptModels.DataSource = man.Models;
        rptModels.DataBind();
}

I always found it annoying that I had to create a ItemDataBound function when the only thing I needed to do was bind the child repeater. However, recently I found out you don’t need to bother with all the above code. You can just do this:

<asp:Repeater ID="rptManufacturers" runat="server">
    <ItemTemplate>
        <%# Eval("Name") %>
        <asp:Repeater runat="server" ID="rptModels" DataSource='<%# Eval("Models") %>'>
            <HeaderTemplate>
                <ul>
            </HeaderTemplate>
            <ItemTemplate>
                <li><%# Eval("ModelName") %></li>
            </ItemTemplate>
            <FooterTemplate>
                </ul>
            </FooterTemplate>
        </asp:Repeater>
    </ItemTemplate>
</asp:Repeater>

This is a really simple solution when the only thing you need to do is bind a child control ( Repeater, DataGrid, GridView, etc ). The solution doesn’t really apply if you need to do more logic on the ItemDataBound event.

Automatic Update of Datamodel In Linq

One of the issues that we came across fairly quickly when converting some projects to Linq was how unusable the default Linq to SQL utility was. The interface worked extremely well for 2 or 3 tables, but quickly became unmanageable with much more than that.

We began looking for other solutions, and discovered a command line utility called SQLMetal that can be used to generate a DataModel from a connection string and/or an XML file.

The solution we settled on uses SQLMetal to generate XML markup from the database, then uses XSL Transformations to make desired property/model changes (Private properties, Delay loaded, etc), and then uses SQLMetal to generate a code file from this XML file.

To start, we created a batch file called updateModel.bat and placed it in the project:

"C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin\SQLMetal.exe" /conn:"CONNECTIONSTRING" 
      /timeout:0 /namespace:MODELNAMESPACE /context:DATACONTEXTNAME /language:csharp /pluralize 
      /dbml:"%~dp0DataModel.dbml"
"%~msxsl.exe" "%~dp0DataModel.dbml" "%~dp0ModifyDbml.xslt" -o "%~dp0DataModel.dbml"
"C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin\SQLMetal.exe" /code:"%~dp0DataModel.cs"
    /namespace:MODELNAMESPACE /context:DATACONTEXTNAME /language:csharp 
    /pluralize %DataModel.dbml

The output of SQLMetal in the first line of this file is an XML file called DataModel.dbml that looks something like this :

  <Table Name="dbo.Person" Member="Persons">
    <Type Name="Person">
      <Column Name="PersonID" Type="System.Int32" DbType="Int NOT NULL IDENTITY" IsPrimaryKey="true" IsDbGenerated="true" CanBeNull="false"></Column>
      <Column Name="AddressID" Type="System.Int32" DbType="Int NOT NULL" CanBeNull="false"></Column>
      <Column Name="Email" Type="System.String" DbType="VarChar(255) NOT NULL" CanBeNull="false"></Column
      <Column Name="NameFirst" Type="System.String" DbType="VarChar(255) NOT NULL" CanBeNull="false"></Column>
      <Column Name="NameLast" Type="System.String" DbType="VarChar(255) NOT NULL" CanBeNull="false"></Column>
<Association Name="FK_Person_Address" Member="Address" ThisKey="AddressID" OtherKey="AddressID" Type="Address" IsForeignKey="true"></Association>
    </Type>
  </Table>

The second line of this script uses a utility called msxsl.exe (note that this requires MSXML). This program uses a file called ModifyDbml.xslt to perform an XSL tranformation on the DataModel.dbml file.

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
								xmlns:dbml="http://schemas.microsoft.com/linqtosql/dbml/2007"
								xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
								xmlns:msxsl="urn:schemas-microsoft-com:xslt"
								exclude-result-prefixes="msxsl">
  <xsl:output method="xml" indent="yes"/>

  <xsl:template match="dbml:Database/dbml:Table/dbml:Type[@Name = 'Person']/dbml:Column[@Name = 'AddressID']">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()" />
       <xsl:attribute name="AccessModifier">Private</xsl:attribute>
    </xsl:copy>
  </xsl:template>

<xsl:template match="@* | node()">
     <xsl:copy>
      <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

This will make it so the “AddressID” property of “Person” is a private property – and this is where all such DataModel changes should be stored. Note that any changes made directly to the DataModel after this point will be lost each time the files are generated.

The final line of this script generates a DataModel.cs file from the updated XML file.

Finally, we looked for a way to call this script to update from within visual studio. To do this, we went to Tools -> External Tools -> Add, and used the following arguments:

This allows you to highlight the updateModel.bat from Visual Studio and go to “Tools->CMD Prompt” to update your DataModel.

bindWithDelay jQuery Plugin

Sometimes, I want to have a JavaScript event that doesn’t fire until the native event stops firing for a short timeout. I’ve needed to use that pattern in almost every project I have worked on.

For example, you want to use JavaScript to resize an iframe to 100% height when the window resizes. The resize() event can fire dozens of times, and calculating and setting the new height can slow down your page. I used to implement it like this:

var timeout;
function doResize(e) {
   clearTimeout(timeout);
   timeout = setTimeout(function() {
      // run some code
   }, 200);
}
$(function() {
   $(window).bind("resize",doResize);
});

Notice that there are extra variables that you have to deal with, and extra indentation. You could at least clean up the global variable using closures, but you get the idea.

I wrote a plugin to make this pattern easier, it is called “bindWithDelay”. The source code is online, as is a mini project page with a demo.

This is what the same code looks like with the plugin:

function doResize(e) {
      // run some code
}
$(function() {
   $(window).bindWithDelay("resize", doResize, 200);
})

IEnumerable.Flatten in C#

One thing I’ve seen fairly often is this:


public IEnumerable<Relationship> GetRelationships()
{
     var itemRels = (from i in DataContext.Items
                      select i.Relationships);

     var relList = new List<Relationship>();
     foreach (var rels in itemRels) {
          relList = relList.Concat(rels).ToList();
     }

     return relList;
}

This is essentially the same as the “Flatten” function that exists in many other languages, i.e.

var array = [1,2][3][4,5,6].flatten() // array = [1,2,3,4,5,6];

There is a built in extension for selecting objects like this in Linq :

     return Datacontext.Items.SelectMany(i => i.Relationships);

Changing .Net Framework version on a website in IIS without restarting the W3SVC process

If you are changing the .Net Framework version of a website hosted in IIS  you will most likely receive a message that looks like the following

The problem is that if you restart the W3SVC, all the application pools will be recycled.  In my case we are hosting multiple versions of the site in IIS (Live, Staging, etc.).  I didn’t want to recycle every application pool if I didn’t need to.  Plus, if you are storing state information in the worker process it will be lost when the application pool gets recycled.

The dialog points to a command you can run in order to keep the W3SVC process from restarting.  The command is pretty straight forward except for the “IIS-Virtual-Path” part.  The “IIS-Virtual-Path” is the path IIS uses in order to differentiate between sites.  This path is in the form “W3SVC/Site ID/root”.  To find the Site ID, just click on the “Web Sites” folder in IIS and you should see a table in the right column that looks similar to this:

IIS 6

IIS 7

Once you find the Site ID, open up a command prompt window and navigate to the folder of the framework version you are wanting to change to.  The framework version folders are usually found in c:/Windows/Microsoft.Net/Framework/.  Once you are inside the folder  you can just run the following command for a site with the ID 1957079098:

aspnet_regiis.exe -norestart -s W3SVC/1957079098/root/

After you update the framework version, you will still need to restart the application pool for the website that you are changing though.

Threading with Impersonation in an ASP.NET Project

Add to FacebookAdd to DiggAdd to Del.icio.usAdd to StumbleuponAdd to RedditAdd to BlinklistAdd to TwitterAdd to TechnoratiAdd to Yahoo BuzzAdd to Newsvine

Every once in a while, you might run into a need to do something that takes some time in a web app, but doesn’t require user interaction. Maybe you are processing an uploaded file (rescaling images, unzipping, etc). Maybe you are rewriting some statistical data based on new posts. Basically, something that takes minutes or hours – but isn’t that important to be interactive with the user.

You could set up a “job” in a database to be run the next time your timer runs (see https://lanitdev.wordpress.com/2010/03/16/running-a-scheduled-task/). If you don’t have a timer yet, though, that can be overkill if you don’t care that multiple jobs may run at once.

In my case, I needed to export a large volume of data to a zip file. I asked up front for an email address – and the user will receive a link to the completed zip in an email later. The job would only be performed by admins, and even then only about once a year – so there was no need to schedule the job – I could just fire it off when the user requested it.

Any easy way to do this is to use the .NET threading objects in System.Threading. Because I need to save a file, I also have one additional issue – Threads don’t automatically run under the same account that the site does, so I had to include code to impersonate a user that has write permissions.

Here’s a bit of code to get you started:

// param class to pass multiple values
private class ExportParams
        {
            public int UserID { get; set; }
            public string Email { get; set; }
            public string ImpersonateUser { get; set; }
            public string ImpersonateDomain { get; set; }
            public string ImpersonatePassword { get; set; }
        }

        protected void btnExport_Click(object sender, EventArgs e)
        {
//  .... code to get current app user, windows user to impersonate .....

            Thread t = new Thread(new ParameterizedThreadStart(DoExport));
            t.Start(new ExportParams(){
                UserID=CurrentUserID,
                Email=txtEmail.Text,
                ImpersonateUser = username,
                ImpersonateDomain = domain,
                ImpersonatePassword = password
            });
             // show user 'processing' message .....
         }

        private void DoExport(object param)
        {
            ExportParams ep = (ExportParams)param;

            using(var context = Security.Impersonate(ep.ImpersonateUser , ep.ImpersonateDomain,
             ep.ImpersonatePassword ))
          {
            // do the work here..............
          }
        }

Here’s the relevant part of the Security class that does the impersonation:

using System.Runtime.InteropServices;
using System.Security.Principal;
// .....
public class Security {
//.............
public const int LOGON_TYPE_INTERACTIVE = 2;
        public const int LOGON_TYPE_PROVIDER_DEFAULT = 0;
        // Using this api to get an accessToken of specific Windows User by its user name and password
        [DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
        static public extern bool LogonUser(string userName, string domain, string passWord, int logonType, int logonProvider, ref IntPtr accessToken);

        public static WindowsImpersonationContext Impersonate()
        {
            return Impersonate("DEFAULT_USER","DEFAULT_DOMAIN","DEFAULT_PASSWORD");
        }
        public static WindowsImpersonationContext Impersonate(string username, string domain, string password)
        {
            IntPtr accessToken = IntPtr.Zero;
            //accessToken.Debug();
            var success = LogonUser(username, domain, password, LOGON_TYPE_INTERACTIVE, LOGON_TYPE_PROVIDER_DEFAULT, ref accessToken);

            //accessToken.Debug();
            if (!success)
                return null;

            WindowsIdentity identity = new WindowsIdentity(accessToken);

            return identity.Impersonate();
        }
// ..........
}

Radio button within a repeater problem

Recently I was developing a system to create tests and test questions.  For these tests our client wanted multiple choice questions.  To implement this I decided to have a list of textboxes for the answer text, and a radio button for each textbox to select the correct answer.   I knew that a RadioButtonList couldn’t have anything other than a radio button and text, so I went with a repeater.

<asp:Repeater ID="rptRadios" runat="server">
    <HeaderTemplate>
        <ul>
    </HeaderTemplate>
    <ItemTemplate>
        <li>
            <asp:RadioButton ID="rbRadio" runat="server" GroupName="RadioGroup" />
            &nbsp;
            <asp:TextBox runat="server" ID="txtRadio"></asp:TextBox>
        </li>
    </ItemTemplate>
    <FooterTemplate>
        </ul>
    </FooterTemplate>
</asp:Repeater>

Doing it this way caused the group name of each radio button to be inconsistent, because of the repeater. After a while of researching and not finding any good solutions I decided to try changing the group name of the radio buttons using jQuery.

$("input:radio").attr('name', 'RadioGroup');

That gave me the radio button functionality that I wanted, but it prevented me from getting the selected radio button on postback. So I decided to just implement the radio button functionality manually.

var radios = $("input:radio");
radios.click(function() {
     radios.removeAttr('checked');
     $(this).attr('checked', 'checked');
     return true;
});

Which gave me the correct functionality and I could still get the selected radio button and textbox on postback. Probably not the most elegant solution, but I couldn’t find any other way to do it.

Also I needed to make sure at least one of the radio buttons was selected so I added a CustomValidator that called a javascript function.

function ValidateRadioButtons(sender, args) {
     args.IsValid = $("input:radio:checked").size() > 0;
}