Code Sprouts

Wholesome Bits Of Tech

Programatically Add Mime Types In IIS 7.0

clock February 28, 2009 15:25 by author ColinW
While Mime Types are simple to add through the IIS 7.0 Configuration Manager, there are occasions where you’ll need to add them programmatically.  While there are several shell-driven options available ( powershell or the appcmd.exe utility ), IIS 7.0 includes a managed interface that is quite powerful in what it provides. 
 

The actual code interface lies in the Microsoft.Web.Administration.dll, and can be found in the IIS directory in your %WINDOW%\System32\inetsrv folder.  The entire interface revolves around the ServerManager class, which is the entry-point into the IIS configuration system.  With the ServerManager class, you can do everything from creating and managing sites, applications and virtual directories, to directly modify the IIS configuration files.

As an example, I created some sample code to add a .xap ( Silverlight ) mime-type to IIS for a silent install on a client machine:
 
ServerManager serverManager = new ServerManager();
string extension = ".xap";
string mimeType = "application/x-silverlight-app";

// Pulll the config for the default website
Configuration webConfig = serverManager.GetWebConfiguration("Default Web Site");

// mime maps live in Configuration/system.webServer/staticContent 
ConfigurationSection staticContentSection = webConfig.GetSection("system.webServer/staticContent");

// let's check if the current map exists
var existingMimeMap = from mimeMaps in staticContentSection.GetCollection()
                      where mimeMaps.Attributes["fileExtension"].Value.ToString().ToLower() == extension.ToLower()
                      select mimeMaps;

if (existingMimeMap.Count() == 0)
{
    // Configuration elements must be created by the collection that will consume it
    ConfigurationElement mimeMapElement = staticContentSection.GetCollection().CreateElement("mimeMap");
    
    // set the attributes for the map
    mimeMapElement.SetAttributeValue("fileExtension", extension);
    mimeMapElement.SetAttributeValue("mimeType", mimeType);

    staticContentSection.GetCollection().Add(mimeMapElement);

    // after commit, the mimetype will be active for the current site
    serverManager.CommitChanges();
}

And that’s all that’s required to open the configuration, add mime-type, and save the changes back to IIS.  Once CommitChanges is called, you can immediately see the results reflected in IIS ( in this case, you’ll be able to download Silverlight .xap files ).

The managed interface is quite powerful in it’s capabilities, and I’ll be covering more of it’s features in future posts.

- Colin



Focusing a Silverlight Control On Startup

clock February 19, 2009 19:18 by author ColinW

In the Silverlight applications I’ve been working with recently, it seems that when you call focus on a control during startup, nothing appears to happen visually.  I”m not sure if the root cause of the issue lies in the browser ( IE 7) or in Silverlight, as the work-around involves both.

In Silverlight, you’ll need to use the Dispatcher to execute your focus code:

Dispatcher.BeginInvoke(() => input3.Focus());

And in the actual page hosting the application, you’ll need to call .focus on the Silverlight control in Javascript:

setTimeout(function() { document.getElementById('Xaml1').focus();  }, 1);

What’s interesting is that both pieces of code delay the execution of the actual focus calls until after their current threads are running, and in the case of the javascript call, focusing does not work correctly if you use a timeout period of 0.

My guess is that a future version of Silverlight will remove the requirement of wrapping the focus call in a Dispatcher Invoke, but we’ll be stuck with IE not setting focus for a while.

- Colin



Adding An Entity Framework Model To An MVC Project

clock February 19, 2009 18:47 by author ColinW
While the Entity Data Model Wizard takes care of most of the housekeeping chores when you add an entity model to your project, it fails to add the necessary reference to your web.config in order for you to reference an Entity from your model. 
 
If you try to access an entity from a view or any other code-front, you end up with the following error:
 
Compiler Error Message: CS0012: The type 'System.Data.Objects.DataClasses.EntityObject' is defined in an assembly that is not referenced. You must add a reference to assembly 'System.Data.Entity, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.
 
While the message is quite descriptive, it doesn’t tell you that the reference needs to be added to the web.config, not just in the project references. 
 
The required line you need to add in the assemblies section of your web.config is:
 

<add assembly="System.Data.Entity, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />

I do not think this issue will be resolved in the first release of MVC, as the change would really need to be done in Visual Studio, so be prepared to do a little manual work for the near future.

- Colin



TextChanged When You Least Expect It

clock February 17, 2009 18:16 by author ColinW

While working on a WPF project last week, I ended up in a situation where I needed a TextBox with a TextBlock below it that needed to keep it’s display synchronized with whatever was in the TextBox.  I figured the easiest way to do it would be to just listen for the TextChanged event and then set the TextBlock text to the value of the TextBox Text. 

So I added the XAML:

<TextBox x:Name="input" TextChanged="input_TextChanged">Test Data</TextBox>
<TextBlock x:Name="output" />
 
I added the code-behind:
 
private void input_TextChanged(object sender, TextChangedEventArgs e)
{
    output.Text = input.Text;
}

And I ran the application:

image

Well that’s a bit… unexpected!

So What Happened?

What happened is that when WPF adds the textbox to the control tree, it wires up the TextChanged event before it sets the default text, which causes the TextChanged event to fire.  Since WPF hasn’t added the TextBlock to the control tree yet and it’s a null reference, my code that tries to set the text on that TextBlock fails, and an exception is born.

What’s unusual to me is that this is NOT the same behavior you would see in a Windows Forms application.  If you recreate a similar application in Windows Forms with a TextBox and a Label, an exception is not thrown when the form is initialized.  In fact, the TextChanged event is not even fired, it only starts firing after the form is up and running.

But back to the exception, how do you fix it? 

If you want to solve the issue in code, you’ll need to check for null to avoid throwing an exception:

if ( output != null )
    output.Text = input.Text;

But this isn’t optimal, as on the initial load you’ll have an empty TextBlock that’s not in sync with the TextBox.  We can do better by eliminating the event handler completely and switching techniques to using data binding:

<TextBox x:Name="input">Test Data</TextBox>
<TextBlock x:Name="output" Text="{Binding ElementName=input, Path=Text}" />

And we now end up with exactly what we wanted: A TextBlock underneath a TextBox that stays in sync with the contents of the TextBox. Beautiful!

- Colin



Code Tip #1: Dynamic Where Clause in LINQ

clock February 16, 2009 17:52 by author ColinW

Most data-driven applications have need a search function that’s driven off a user submitted list of keywords.  In pre-LINQ days, this using entailed looping through the keywords and building up a string to execute on the data source ( On SQL Server, you would be handing a string off to the EXEC command). 

This approach is less than desirable for several reasons, including:

  • It’s error prone, as it requires fiddling with control characters and correctly escaping them
  • SQL Data Sources are susceptible to SQL Injection
  • There’s no type safety, and the resulting query may not query the right columns, or mismatch data types

While you can limit a few of these issues by using varying techniques ( parameters and stored procedures eliminate some of the security issues in SQL Server ), you’re still stuck with an unwieldy way of generating a string-based statement to query against your data source. 

The LINQ Way

Thanks to LINQ, we can forget about all the issues related to building up a string-based query and use one of the more powerful features of LINQ to our advantage: Deferred Execution. 

Deferred Execution is a feature of LINQ that delays the execution of your query until data is actually requested from it.  Using deferred execution, we can repeatedly modify a query to add additional expressions to it, without paying any data access penalty. 

For example, take the following data source:

List<string> items = new List<string>();

items.Add("Laurie");
items.Add("Joe");
items.Add("Chris");
items.Add("Melissa");

If we query the data as is:

var query = from item in items
            select item;

We would see the following results:

Laurie
Joe
Chris
Melissa
 
 
Now, suppose the user wanted to search by two keywords, “a” and “e”:
// Mimic user input
string[] keywords = new string[] { "a", "e" };

In order to restrict the results, we need to add each keyword to our query:

keywords.ToList().ForEach(keyword =>
            query = from item in query
                    where item.ToLower().Contains(keyword.ToLower())
                    select item
                          );

Or, if you prefer the all-lambda way:

keywords.ToList().ForEach(keyword => query = query.Where(item => item.ToLower().Contains(keyword.ToLower())));

And now, if we look at the results of our query:

var results = from item in query
              select item;

We end up with the following:

Laurie
Melissa

And that’s exactly what we wanted!

In this example I’m only using LINQ to objects, but the results are the same regardless of the provider.  One interesting thing to note is that if you do use LINQ to SQL or LINQ to Entities, the resulting query will look very similar to what you would build by hand using a string-based approach.  While that might make LINQ seem like overhead, keep in mind that LINQ is providing you with compile-time checks for all the issues I stated above ( control character manipulation, SQL Injection, type safety, etc. ).  All very good things to have!

- Colin



Including Ajax & JQuery into ASP.Net MVC

clock February 8, 2009 13:25 by author ColinW

While the latest RC of the the MVC Framework does include Microsoft's Ajax script libraries and JQuery 1.2.6, they're not accessible without manually inserting the script includes yourself.  In order to get up and running with the scripts, you'll need to include the following script references in your frontend code:

<script src="<%= Url.Content("~/Scripts/MicrosoftAjax.debug.js") %>" type="text/javascript"></script>

<script src="<%= Url.Content("~/Scripts/MicrosoftMvcAjax.debug.js") %>" type="text/javascript"></script>

<script src="<%= Url.Content("~/Scripts/jquery-1.2.6.js") %>" type="text/javascript"></script>

I like to include these scripts in the header tag of my master page(s), that way I can set them once and then forget about them.  If the footprint from the size of the scripts is an issue, you can always just manually include the scripts only on the page(s) that need jquery and/or ajax functionality.

 - Colin



The Web Application Root Operator in MVC

clock February 8, 2009 12:24 by author ColinW

When writing URI paths in ASP.Net, one of the most useful features the run-time provides you with is the web application root operator. The operator is nothing more than the tilde (~) character, yet it gives you the ability to start any path from the root of your website without having to resort to using multiple directory-up (..\) directives to set the path you need. 

For example, take the scenario where your current page being processed is located at 'http://www.yoursite.com/Pages/Admin/Email.aspx', and you want to add an ImageButton that reference an image in the folder 'http://www.yoursite.com/Images/sendmail.jpg'.  Without the web application root operator, you would have to write something similar to the following:

<asp:ImageButton ID="sendMail" runat="server" ImageUrl="../../Images/sendMail.jpg" />

While this works, it's far from ideal as the link to the image will break if the page hosting the ImageButton changes location, or if someone copy/paste's your ImageButton code into a different page with a different relative path. 

However, using the web application root operator, you can simply write the control as follows:

<asp:ImageButton ID="sendMail" runat="server" ImageUrl="~/Images/sendMail.jpg" />

Now, it no longer matters where the page hosting this ImageButton control resides, the path will always be the root of the application + /Images/sendMail.jpg.  The page may change paths, or someone may copy the code, but the path will always stay the same.  This ends up being a much more robust solution, and looks much cleaner as well.  There is one drawback, however, and that is the operator is only available to server-side controls, and cannot be used in client-side html elements.

Since the MVC framework does away with the use of most server controls, it first appears that using relative paths is the only way to go.  Fortunately, there's a better option, the UrlHelper.Content() method!

In the current UrlHelper class, there's now a method called Content, which accepts a virtual path and turns it into an absolute path.  The virtual path that is passed in can be pre-pended with the ~, and it works exactly as it does in ASP.Net:

 <img src="../../Images/sendmail.jpg" />  

Can be replaced with:

<img src="<%= Url.Content("~/Images/sendmail.jpg") %>" />

The syntax is a bit longer, however you still get the same benefits of starting your path off with the application root, instead of trying to navigate around using relative paths.

- Colin



Hello World!

clock February 5, 2009 17:28 by author ColinW

Welcome to Code Sprouts!

My intent with this blog is to provide a learning resource for myself as well as others for various technologies found in todays development world.  Most of the focus will related to my career as a Consultant with Magenic Technologies, so we're going to be seeing a pretty heavy slant here towards Microsoft products.

So here she is folks, all primed up and ready to go!