Monday, August 18, 2008

Validate a file path using C#

I finally found a good algorithm to validate a file path (had to fix two bugs in it though). I use this static method in Windows Forms when the user is allowed to enter a path. I add a text changed event on the textbox and call this method to enable or disable an OK button.

public static bool ValidateFilepath(string path)
{
if (path.Trim() == string.Empty)
{
return false;
}

string pathname;
string filename;
try
{
pathname = Path.GetPathRoot(path);
filename = Path.GetFileName(path);
}
catch (ArgumentException)
{
// GetPathRoot() and GetFileName() above will throw exceptions
// if pathname/filename could not be parsed.

return false;
}

// Make sure the filename part was actually specified
if (filename.Trim() == string.Empty)
{
return false;
}

// Not sure if additional checking below is needed, but no harm done
if (pathname.IndexOfAny(Path.GetInvalidPathChars()) >= 0)
{
return false;
}

if (filename.IndexOfAny(Path.GetInvalidFileNameChars()) >= 0)
{
return false;
}

return true;
}

Plug-in architecture (dynamically loading DLLs) using LINQ

For implementing a plug-in architecture using the strategy pattern, this is my preferred way of loading some interfaces (DLLs) at runtime. Make sure you look at the second code example showing how to do the same thing in LINQ.

public List<T> LoadDLL<T>(string path, string pattern)
{
    List<T> plugins = new List<T>();
    foreach (string s in Directory.GetFiles(Path.GetFullPath(path), pattern))
    {
        foreach (Type t in Assembly.LoadFile(s).GetTypes())
        {
            if (!t.IsAbstract && typeof(T).IsAssignableFrom(t))
            {
                plugins.Add((T)Activator.CreateInstance(t));
            }
        }
    }

    return plugins;
}

Now using LINQ...
public List<T> LoadDLL<T>(string path, string pattern)
{
    return Directory.GetFiles(Path.GetFullPath(path), pattern)
        .SelectMany(f => Assembly.LoadFile(f).GetTypes()
            .Where(t => !t.IsAbstract && typeof(T).IsAssignableFrom(t))
            .Select(t => (T)Activator.CreateInstance(t)))
        .ToList();
}

If you want to load an assembly and all the dependent DLLs, you can use the same LINQ query, but use LoadFrom rather than LoadFile.

public List<T> LoadDLL<T>(string path, string pattern)
{
    return Directory.GetFiles(Path.GetFullPath(path), pattern)
        .SelectMany(f => Assembly.LoadFrom(f).GetTypes()
            .Where(t => !t.IsAbstract && typeof(T).IsAssignableFrom(t))
            .Select(t => (T)Activator.CreateInstance(t)))
        .ToList();
}

This can then be called using:
List<Foo> foos = LoadDLL<Foo>(@".\", "*.dll");

Thursday, August 14, 2008

Replacing delegates with lamda expressions

If you understand a lamda expression, you realized that it is just another step in the evolution of delegates. Now that Visual Studio intellisense and the .NET compiler can infer from a delegate declaration what parameters are required for a delegate, and their types, we no longer have to use the "delegate" keyword or the parameter types...we just need to specify some parameter names.

For example, an older style event delegate would be done like:

x.Completed += delegate(object sender, EventArgs e) { ... };

Now all we need to code is:

x.Completed += (sender, e) => { ... };

Again, the development environment already knows that the Completed event needs two parameters, a object and a EventArgs; there is no need for us to supply those pieces of information.

Saturday, August 9, 2008

PowerShell and CSV files

If you need to process a CSV file, you can use PowerShell's import-csv command. If headers exist in the first line of the CSV, then they will be used as property names on the resulting import-csv output. For example, if you CSV looks like:

Last,First,Middle
Jones,Fred,S
Smith,Sally,M
Johnson,Bob,L

Then you can output the full names like:

import-csv employees.csv |% `
{[string]::format("{0} {1} {2}",$_.first, $_.middle,$_.last)}

Or if you only want last names that start with a "J", you can:

import-csv employees.csv | `
where {$_.last.startswith("J")} |% `
{[string]::format("{0} {1} {2}",$_.first, $_.middle,$_.last)}

Pretty cool, eh?

PowerShell v2 will have the ability to change what the delimiting character is.

Thursday, August 7, 2008

Format C# code for Blogger posts

This is the tool I like for formatting C# source code in my blog.

http://formatmysourcecode.blogspot.com/

Using ListView and LINQ to display multi-level relationships



This is cool! Assume we have a database that has a three-level relationship. We have a Product, Install, and Document table. Products have installations and installations have related documents for them. This means our Document table has a InstallId and our Install table has a ProductId. This is all standard relationship stuff so hopefully you are following this.

Now assume we want to use LINQ and the ListView web control to display hierarchical data and we want full control over the HTML generated (that's why we use the ListView control). The display will look like:

Product P1
  Installation I1
    Document D1
    Document D2
  Installation I2
    Document D3
Product P2
...

First, use a standard LINQ-to-SQL class in Visual Studio to create your data context object. Next, create a three-level set of ListView objects. Here's the cool part...are you ready for this?

Binding your data: Each ListView needs to be bound to a LINQ IQueryable data source. The outer most ListView, Product, can be just linked to the Products (remember the generated data context adds the plural name to the table name) like:

MultiLevelDataContext db = new MultiLevelDataContext();
IEnumerable<Product> products = db.Products;
lvProduct.DataSource = products;
lvProduct.DataBind();



If you do this in code-behind, that's all you are going to do there. The other two bindings are done in the ListView declaration itself.

The Install and Document nested ListView components just need to have their DataSource property set to the property of its outer ListView object. Remember that when the LINQ-to-SQL code was generated, it automatically added properties for relationship data. For example, the Product class has a property called Installs. The Install class has a property called Documents. These properties basically end up being IQueryable data sources. We simply use a standard Eval() binding statement in the DataSource to connect things up. This makes it incredibly easy to bind the related data into a web control like a three-level ListView structure.

Below is what is all ends up looking like. Two things to mention. Most of the aspx is table formatting. Secondly, notice the DataSource statements in the two nested ListView controls.

Code Behind (cs)

protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
MultiLevelDataContext db = new MultiLevelDataContext();
IEnumerable<Product> products = db.Products;
lvProduct.DataSource = products;
lvProduct.DataBind();
}
}



Web Page (aspx)

<asp:ListView ID="lvProduct" runat="server">
<LayoutTemplate>
<table cellpadding="3" cellspacing="0" border="1" style="width: 100%; background-color: Silver;">
<tr runat="server" id="itemPlaceholder" />
</table>
</LayoutTemplate>
<ItemTemplate>
<tr>
<td>Product:
<%# Eval("Name") %>
</td>
</tr>
<asp:ListView ID="lvInstall" runat="server" DataSource='<%# Eval("Installs") %>'>
<LayoutTemplate>
<tr>
<td>
<table cellpadding="3" cellspacing="0" border="1" style="width: 100%; background-color: Aqua;">
<tr runat="server" id="itemPlaceholder" />
</table>
</td>
</tr>
</LayoutTemplate>
<ItemTemplate>
<tr>
<td>Version:
<%# Eval("Version") %>
</td>
<td>Release Date:
<%# Eval("ReleaseDate") %>
</td>
</tr>
<asp:ListView ID="lvDocuments" runat="server" DataSource='<%# Eval("Documents") %>'>
<LayoutTemplate>
<tr>
<td colspan="2">
<table cellpadding="3" cellspacing="0" border="1" style="width: 100%; background-color: Lime;">
<tr runat="server" id="itemPlaceholder" />
</table>
</td>
</tr>
</LayoutTemplate>
<ItemTemplate>
<tr valign="top">
<td>
<%# Eval("Name") %>
</td>
<td>
<%# Eval("Description") %>
</td>
</tr>
</ItemTemplate>
</asp:ListView>
</ItemTemplate>
</asp:ListView>
</ItemTemplate>
</asp:ListView>

Monday, August 4, 2008

Synchronizing LINQ-to-SQL with database schema

The initial release of the LINQ-to-SQL designer support in VS 2008 doesn't have a good way of keeping changes in the database schema synchronized with the dbml (designer) data. I've really only found two products so far that claim to do this for you.

Huagati DBML Tools
http://www.huagati.com/dbmltools/

Database Restyle by Perpetuum Software
http://www.perpetuumsoft.com/Product.aspx?lang=en&pid=55

I have not personally tried either of these yet.

Can't RDP? How to enable / disable virtual machine firewall for Azure VM

Oh no!  I accidentally blocked the RDP port on an Azure virtual machine which resulted in not being able to log into the VM anymore.  I did ...