Visual Studio 2010 Publish Command from msbuild Command line

Seems like there a bunch of confusion about how to produce the “Publish” behavior provided by Visual Studio 2010 from msbuild 4 command line. The question I keep seeing over and over again is: How do I publsih the output of a web application with web.config tranformations included. This should get the job done:

msbuild solution.sln 
/p:Configuration=Release;DeployOnBuild=true;
DeployTarget=Package;_PackageTempDir=..\publish

ASP.NET MVC and Ruby on Rails Open Source Examples

Recently, I started hosting some “play” projects on GitHub. I have not had much time to write anything up on the details of these projects but I figured I would share the code anyway. First, the MyPhotos example is a jumping off point for a personal photo catalog. Second, the ShowOff project is a real world example of building a portfolio or gallery using ASP.NET MVC. Finally, John V. Peterson was kind enough to share his Nerd Dinner on Rails project. This is a port of the popular ASP.NET MVC real world example Nerd Dinner project.

tmpA6FB

You can find the git repositories for these projects via my account on GitHub.

I am hoping to walk through these projects in future posts. I have some down time due to a recent surgery. Depending on how I feel day to day, I will be working on these upcoming posts to pass the time.

ASP.NET MVC Helper – Dynamic Forms based on Model

Recently, I was working with a fairly complex data model that required a simple input form. Being the lazy programmer I am, I did not feel like crunching out the HTML required to generate this form by hand. So instead, I wrote an HTML helper class to generate the form for me.

Model

Here is the data model we are going to be working with in this example.

public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
    public Address Address{ get; set; }
    public Gender Gender { get; set; }
}

public class Address
{
    public string Address1 { get; set; }
    public string Address2 { get; set; }
    public string City { get; set; }
    public string State { get; set; }
}

public enum Gender
{
    Male,
    Female
}

Goal

The goal here is to have a View that needs only call this helper to generate the textboxes and dropdown lists used for entering data. This way we avoid manually typing all of those angle brackets. So our View will look something like…

 

<h2>Dynamic Form</h2>

<%= Html.ValidationSummary("Create was unsuccessful. Please correct the errors and try again.") %>

<% using (Html.BeginForm()) {%>

<%= Html.DynamicInputs(Model, "Enter Person Information", string.Empty) %>

<p>
    <input type="submit" value="Submit" />
</p>

<% } %>

 

Dynamic Input Helper

The DynamicInputHelper will enumerate the data model properties and output forms elements responsible for receiving input from the user based on the data type. This is pretty simple.

 

public static class DynamicFormHelper
{
    public static string DynamicInputs<T>(this HtmlHelper helper, T obj, string heading, string prefix)
        where T : class
    {

        // Contruct id for model binding
        if (!string.IsNullOrEmpty(prefix))
            prefix += ".";

        // Make sure we have an instance of the obj
        if (obj == null)
            obj = (T)Activator.CreateInstance(typeof(T));

        var type = obj.GetType();

        var sb = new StringBuilder().Append("<fieldset>");

        sb.AppendFormat("<legend>{0}</legend>", heading);

        foreach (var propertyInfo in type.GetProperties())
        {
            if ((propertyInfo.PropertyType.IsValueType && !propertyInfo.PropertyType.IsEnum) || propertyInfo.PropertyType.FullName == typeof(string).FullName)
            {
                sb.AppendFormat(
                    "<p><label for=\"{0}\">{1}:</label>" +
                    "<input type=\"text\" id=\"{0}\" name=\"{0}\" value=\"{2}\"></p>",
                    prefix + propertyInfo.Name,
                    propertyInfo.Name.SpaceCamelCase(),
                    propertyInfo.GetValue(obj, null));
            }
            else if (propertyInfo.PropertyType.IsEnum)
            {
                sb.AppendFormat("<p><label for=\"{0}\">{0}:</label>", propertyInfo.PropertyType.Name.SpaceCamelCase());
                
                sb.Append(
                    helper.SelectFromEnum(propertyInfo.PropertyType,
                    prefix + propertyInfo.PropertyType.Name.SpaceCamelCase()));

                sb.Append("</p>");
            }
            else
            {

                var child = Convert.ChangeType(propertyInfo.GetValue(obj, null) ??
                    Activator.CreateInstance(propertyInfo.PropertyType), propertyInfo.PropertyType);

                sb.AppendFormat(
                    helper.DynamicInputs(child, propertyInfo.Name, prefix + propertyInfo.Name)
                    );
            }
        }

        sb.Append("</fieldset>");
        return sb.ToString();
    }

    public static string SelectFromEnum(this HtmlHelper helper, Type type, string name)
    {
        var sb = new StringBuilder();

        sb.AppendFormat("<select id=\"{0}\" name=\"{0}\">", name);


        foreach (var e in Enum.GetNames(type))
        {
            sb.AppendFormat("<option value=\"{0}\">{1}</option>", (int) Enum.Parse(type, e, true), e.SpaceCamelCase());
        }

        sb.Append("</select>");

        return sb.ToString();
    }

    public static string SpaceCamelCase(this string camelCase)
    {
        if (camelCase == null)
            throw new ArgumentException("Null is not allowed for StringUtils.FromCamelCase");

        var sb = new StringBuilder(camelCase.Length + 10);
        bool first = true;
        char lastChar = '\0';

        foreach (char ch in camelCase)
        {
            if (!first &&
                 (char.IsUpper(ch) ||
                   char.IsDigit(ch) && !char.IsDigit(lastChar)))
                sb.Append(' ');

            sb.Append(ch);
            first = false;
            lastChar = ch;
        }

        return sb.ToString(); ;
    } 
}
 

Finished Product

If all goes according to plan you should end up with a finished product that looks something like this. The coolest part about this form is that it is rendered so the Model Binder will know how to construct the object on the server when the request is received.

tmpE18B

 

Update 9/30/2009: As pointed out in the comments below, check out Input Builders MvcContrib for a more complete and robust solution for your form generation needs.

How to identify slow running queries in Sql Server

Recently, I was trying to pin point the queries in an application that were causing Sql Server to spike the CPU at 100%. This query was helpful in finding the top offenders.

SELECT  creation_time
        ,last_execution_time
        ,total_physical_reads
        ,total_logical_reads
        ,total_logical_writes
        ,execution_count
        ,total_worker_time
        ,total_elapsed_time
        ,total_elapsed_time / execution_count avg_elapsed_time
        ,SUBSTRING(st.text, (qs.statement_start_offset/2) + 1
        ,((CASE statement_end_offset
          WHEN -1 THEN DATALENGTH(st.text)
          ELSE qs.statement_end_offset END
          - qs.statement_start_offset)/2) + 1) AS statement_text
FROM sys.dm_exec_query_stats AS qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) st
ORDER BY total_elapsed_time / execution_count DESC;

 

See this post for more information.

Custom SolutionRoot in TFSBuild

So I’m working through an issue trying to copy the build results from the local build location on the build machine to the drop location. I need to to do this manually because I need my solution to be built exactly the way it is built from the IDE, to keep file references in tact. This should be simple, right? Wrong. It seems that the $(SolutionRoot) property is not set to the value of Local Folder in your build definition. The value for $(SolutionRoot) does not seem to affected by customizing this value.

A simple work around to this is to use the $(Solution) property instead, it actually provides the location of the sln file itself. So with a bit of manipulation we can gather our real solution root location. Here is an example of how we can manipulate the value provided by $(Solution) to get the actual solution root.

<Target Name="AfterCompileSolution">
    <ItemGroup>
        <SolutionOutputs Include="$(Solution)\..\**\*.*" />
    </ItemGroup>

    <Copy SourceFiles="@(SolutionOutputs)" DestinationFolder="$(DropLocation)\$(BuildNumber)\%(Directory)%(RecursiveDir)" ContinueOnError="true" />
</Target>