Monday, June 29, 2009

The other day Dan Moseley from the MSBuild team wrote up a review on the books Amazon page. Here are the contents of the review

I'm a developer on MSBuild; Sayed wrote this book with our encouragement, and we reviewed it for accuracy and completeness, so I can recommend it. The documentation for MSBuild in 2.0 and 3.5 was not great; I consider this something like the missing manual. Unfortunately there aren't many other MSBuild books; fortunately Sayed did a good job on this one.

We're fixing a lot of what's "missing" in MSBuild in the upcoming version 4.0 -- I hope Sayed can do a 2nd edition when that comes out. Plus, our docs should be better then :-)

I'm glad to say that this review was posted as 5 out of 5 and that is the 9th review (out of 9) which has been given 5 stars. When we wrote the book I knew that we had put something together that would really meet a specific need. I'm happy to see that the book has been accepted soo well by everyone and I hope that we are able to write a second edition as Dan mentioned.

Sayed Ibrahim Hashimi

book | msbuild | review
Monday, June 29, 2009 4:31:19 AM (GMT Daylight Time, UTC+01:00)  #    Comments [0]  | 
Thursday, June 25, 2009

My brother Sayed Y. Hashimi just released a new book Pro Android: Developing Mobile Applications for G1 and Other Google Phones.

I'm not an Android developer so I cannot speak about specifics about the content but here is the TOC so you can get a better idea of what the book contains.

  1. Introducing the Android Computing Platform
  2. Getting Your Feet Wet
  3. Using Resources, Content Providers, and Intents
  4. Building User Interfaces and Using Controls
  5. Working with Menus and Dialogs
  6. Unveiling 2D Animation
  7. Exploring Security and Location-Based Services
  8. Building and Consuming Services
  9. Using the Media Framework and Telephony APIs
  10. Programming 3D Graphics with OpenGL
  11. Managing and Organizing Preferences
  12. Coming to Grips with 1.5
  13. Simplifying OpenGL and Exploring Live Folders


Sayed Ibrahim Hashimi

Android | book | Java
Thursday, June 25, 2009 4:26:28 AM (GMT Daylight Time, UTC+01:00)  #    Comments [1]  | 
Wednesday, June 24, 2009

A few weeks ago I blogged about a video that I was in on Channel 9. Since then the creator of the video Russ Fustino has decided to break out his It's All About the Tools series into individual video entries. He has been posting 18 different videos for 18 consecutive days. I think this is a great idea, because it allows people to go right to the content that they are particularly interested in. There are a bunch of different topics covered from Visual Studio DB Pro to using Fiddler and of course my MSBuild Twitter Logger video which was posted just the other day. If you haven't seen this video yet now is your chance, take a look and let me know what you think. I'm interested in making more videos so if you have some specific topics that you think are cool let me know.

 

Sayed Ibrahim Hashimi

Wednesday, June 24, 2009 4:25:34 AM (GMT Daylight Time, UTC+01:00)  #    Comments [0]  | 
Wednesday, June 03, 2009

A long time ago a reader sent me a build script and asked for my thoughts on it. This is my response. In this entry I have marked up his build script with my comments inside of tags like:

  <!-- ****************************************

      My comments inside of these

  ********************************************* -->

I thought that you guys might be interested in this too. Here it is.

< Project DefaultTargets = " Build " xmlns = " http://schemas.microsoft.com/developer/msbuild/2003 " >

 

 

  <!-- ****************************************

  You can pull these out into a seperate file, i.e., CompanyName.BuildTasks.tasks

  ********************************************* -->

   < UsingTask TaskName = " BuildTasks.MoveUpBuildNumber " AssemblyFile = " BuildTasks\bin\Debug\BuildTasks.dll " />

  < UsingTask TaskName = " BuildTasks.ReplaceInFile " AssemblyFile = " BuildTasks\bin\Debug\BuildTasks.dll " />

  < UsingTask TaskName = " BuildTasks.CheckInIntoVSS " AssemblyFile = " BuildTasks\bin\Debug\BuildTasks.dll " />

  < UsingTask TaskName = " BuildTasks.CheckOutFromVSS " AssemblyFile = " BuildTasks\bin\Debug\BuildTasks.dll " />

  < UsingTask TaskName = " BuildTasks.UndoCheckOutFromVSS " AssemblyFile = " BuildTasks\bin\Debug\BuildTasks.dll " />

  < UsingTask TaskName = " BuildTasks.GetLatestFromVSS " AssemblyFile = " BuildTasks\bin\Debug\BuildTasks.dll " />

  < UsingTask TaskName = " BuildTasks.LabelInVSS " AssemblyFile = " BuildTasks\bin\Debug\BuildTasks.dll " />

  < UsingTask TaskName = " BuildTasks.ShowMessageBox " AssemblyFile = " BuildTasks\bin\Debug\BuildTasks.dll " />

 

 

 

  <!-- ****************************************

  In order to create more extensible MSBuild files you should place conditions on Properties.

  For example:

 

  <PropertyGroup Condition="'$(VSSDatabasePath)'==''">

    <VSSDatabasePath>\\rataserv\vss\srcsafe.ini</VSSDatabasePath>

  </PropertyGroup>

 

  When you do this users can create another file, i.e., MyCustomBuild.proj which imports your

  file and just overrides a few values.

  ********************************************* -->

  < PropertyGroup >

    < VSSDatabasePath > \\some\path\here\srcsafe.ini </ VSSDatabasePath >

  </ PropertyGroup >

  <!-- ======================================================================================== -->

 

  <!-- ****************************************

  Also for extensibility your DependsOnTargets should always be pulled from a property

  which pre-prendes its values to the property itself. So that is:

 

  <PropertyGroup>

    <BuildDependsOn>

      PrebuildAndRun;

      CheckInDeliverables;

      $(BuildDependsOn);

    </BuildDependsOn>

  </PropertyGroup>

 

  In this manner external files can extend the behavior of the Build target. Without this it is going

  to be difficult for people to effectively customize the build process.

  ********************************************* -->

  < Target Name = " Build " DependsOnTargets = " PrebuildAndRun;CheckInDeliverables " >

  </ Target >

 

  <!-- ****************************************

  Be careful with names. I would recommend using a naming convention that will ensure

  that your Targets/Properties/Items do not collide with each other.

  For example if I create re-usable .targets files and many of them have a "Build" target

  then I cannot user more than 1 at a time via an <Import ..>. Which is how I like for

  reusable .targets files to be used. For example using a prefix such as in my case SedoConfig or SedoDB.

  Do I need to expand on this?

  **************************************** -->

 

  <!-- ****************************************

  All "Important" targets should have Before and After targets which are on

  the DependsOnTargets property. So that would be:

 

 

  <PropertyGroup>

    <BuildDependsOn>

      BeforeBuild;

      PrebuildAndRun;

      CheckInDeliverables;

      AfterBuild;

      $(BuildDependsOn);

    </BuildDependsOn>

  </PropertyGroup> 

 

  <Target Name="Build" DependsOnTargets ="$(BuildDependsOn)"/>

  <Target Name="BeforeBuild"/>

  <Target Name="AfterBuild"/>

  **************************************** -->

 

 

  <!-- ****************************************

  All the files that you need to checkout can be placed inside of an item and then

  you can batch the usage of the BuildTasks.CheckOutFromVSS task. The item would

  have to have custom metadata of DatabasePath, FilePathInVss and WorkingDirectory.

  So that would be:

 

  <ItemGroup>

    <FilesToCheckOut Include="BuildNumberLP.txt">

      <DatabasePath>$(VSSDatabasePath)</DatabasePath>

      <FilePathInVSS>$/Source/src/LP/BuildNumberLP.txt</FilePathInVSS>

      <WorkingDirectory>LP</WorkingDirectory>

    </FilesToCheckOut>

    <FilesToCheckOut Include="DatabasePackages.sql">

      <DatabasePath>$(VSSDatabasePath)</DatabasePath>

      <FilePathInVSS>$/Source/src/LP/DatabaseScripts/DatabasePackages.sql</FilePathInVSS>

      <WorkingDirectory>LP/DatabaseScripts</WorkingDirectory>

    </FilesToCheckOut>

   

  </ItemGroup>

  <Target Name="PrebuildAndRun">

   

    <BuildTasks.CheckOutFromVSS

      DatabasePath="%(FilesToCheckOut.DatabasePath)"

      FilePathInVSS="%(FilesToCheckOut.FilePathInVSS)"

      WorkingDirectory="%(FilesToCheckOut.WorkingDirectory)"

   />

 

 

  </Target>

  **************************************** -->

 

  <!-- ****************************************

    The value for DatabasePath probably could just be taken from $(VSSDatabasePath)

    still. It depends on if you might pull files from more than one repository.

    **************************************** -->

 

  < Target Name = " PrebuildAndRun " >

    < Message Text = " building $(MSBuildProjectFile) " Importance = " high " />

    < Message Text = " ------ PATCHING FILES WITH BUILD NUMBER " Importance = " high " />

    <!-- check out file that stores the version incremented on each release build -->

    < BuildTasks.CheckOutFromVSS

      DatabasePath = " $(VSSDatabasePath) "

      FilePathInVSS = " $/Some/Path/Here/BuildNumberLP.txt "

      WorkingDirectory = " LP "

   />

    <!-- check out source files we gonna patch -->

    < BuildTasks.CheckOutFromVSS

      DatabasePath = " $(VSSDatabasePath) "

      FilePathInVSS = " $/Some/Path/Here/DatabaseScripts/DatabasePackages.sql "

        WorkingDirectory = " LP/DatabaseScripts "

   />

    < BuildTasks.CheckOutFromVSS

      DatabasePath = " $(VSSDatabasePath) "

      FilePathInVSS = " $/Some/Path/Here/AssemblyInfo.cs "

      WorkingDirectory = " LP "

   />

    < BuildTasks.CheckOutFromVSS

      DatabasePath = " $(VSSDatabasePath) "

      FilePathInVSS = " $/Some/Path/Here/Properties/AssemblyInfo.cs "

      WorkingDirectory = " LPinstaller/Properties "

   />

    <!-- check out deliverables -->

    < BuildTasks.CheckOutFromVSS

      DatabasePath = " $(VSSDatabasePath) "

      FilePathInVSS = " $/Some/Path/Here/Release/LPSetup.msi "

      WorkingDirectory = " LPSetup/Release "

   />

    < BuildTasks.CheckOutFromVSS

      DatabasePath = " $(VSSDatabasePath) "

      FilePathInVSS = " $/Some/Path/Here/Release/setup.exe "

      WorkingDirectory = " LPSetup/Release "

   />

 

 

    <!-- ****************************************

    The value passed to file could be taken from a property

    so that it can be overridden by another user.

    **************************************** -->

    <!-- PATCH!  -->

    < BuildTasks.MoveUpBuildNumber

    File = " LP/BuildNumberLP.txt " >

      < Output TaskParameter = " BuildNumber " PropertyName = " BuildNumber " />

    </ BuildTasks.MoveUpBuildNumber >

 

    <!-- <Message Text="Build number for the new build will be:$(BuildNumber)" Importance="high" /> -->

    < BuildTasks.ReplaceInFile

        SearchString = " PACKAGE_REVISION "

        ReplaceString = " $(BuildNumber) "

        FileName = " LP/DatabaseScripts/DatabasePackages.sql "

   />

    < BuildTasks.ReplaceInFile

        SearchString = " 27857 "

        ReplaceString = " $(BuildNumber) "

        FileName = " LP/AssemblyInfo.cs "

   />

    < BuildTasks.ReplaceInFile

        SearchString = " 27857 "

        ReplaceString = " $(BuildNumber) "

        FileName = " LPinstaller/Properties/AssemblyInfo.cs "

   />

    < Message Text = " ------ PATCHING FILES WITH BUILD NUMBER... DONE " Importance = " high " />

    <!-- ****************************************

    To get to devenv you could also use:

      $(VS80COMNTOOLS)..\IDE\devenv.com</Devenv>

    **************************************** -->

    <!-- ====================================== -->

    <!-- now build the entire solution including the setup packaging in release mode -->

    <!-- <MSBuild Projects="LP/LP.SLN" Properties="Configuration=Release"/> -->

    < Exec Command = " &quot; C:\Program Files\Microsoft Visual Studio 8\Common7\IDE/devenv.com &quot; &quot; .\LP\LP.SLN

      &quot; /build &quot; Release &quot; /project ..\LPSetup\LPSetup.vdproj /projectconfig &quot; Release &quot; " />

    <!-- ====================================== -->

    < OnError ExecuteTargets = " RecoverFromError " />

  </ Target >

  <!-- ======================================================================================== -->

  < Target Name = " CheckInDeliverables " >

 

 

    <!-- ****************************************

    You could use the same item as you used in the BuildTasks.CheckOutFromVSS

    step here.

    **************************************** -->

    < Message Text = " ------ CHECKING IN CHANGED FILES " Importance = " high " />

    <!-- check the file with new version back into VSS -->

    < BuildTasks.CheckInIntoVSS

      DatabasePath = " $(VSSDatabasePath) "

      FilePathInVSS = " $/Some/Path/Here/LP/BuildNumberLP.txt "

      WorkingDirectory = " LP "

   />

    <!-- ****************************************

    Since you are performing two different actions CheckIn and UndoCheckout

    you would need another piece of metadata on the item lets say, i.e. CheckInAfterEdit,

    then on your CheckInIntoVSS task usage you would place the condition

       Condition="'%(FilesToCheckOut.CheckInAfterEdit)'=='true'"

    that way you would create a batch of files to check in and pass it to the task.

    On your UndoCheckOut you would jus inver the == to !=.

    **************************************** -->

    <!-- revese the assemblies and script files to the "search  marker" that

    gets updated on patching by the build version -->

    < BuildTasks.UndoCheckOutFromVSS

      DatabasePath = " $(VSSDatabasePath) "

      FilePathInVSS = " $/Some/Path/Here/DatabaseScripts/DatabasePackages.sql "

      WorkingDirectory = " LP/DatabaseScripts "

   />

    < BuildTasks.UndoCheckOutFromVSS

      DatabasePath = " $(VSSDatabasePath) "

      FilePathInVSS = " $/Some/Path/Here/LP/AssemblyInfo.cs "

      WorkingDirectory = " LP "

   />

    < BuildTasks.UndoCheckOutFromVSS

      DatabasePath = " $(VSSDatabasePath) "

      FilePathInVSS = " $/Some/Path/Here/LPinstaller/Properties/AssemblyInfo.cs "

      WorkingDirectory = " LPinstaller/Properties "

   />

    <!-- checkin deliverables we just built  -->

    < BuildTasks.CheckInIntoVSS

      DatabasePath = " $(VSSDatabasePath) "

      FilePathInVSS = " $/Some/Path/Here/Release/LPSetup.msi "

      WorkingDirectory = " LPSetup/Release "

   />

    < BuildTasks.CheckInIntoVSS

      DatabasePath = " $(VSSDatabasePath) "

      FilePathInVSS = " $/Some/Path/Here/Release/setup.exe "

      WorkingDirectory = " LPSetup/Release "

   />

    <!-- Label as the new version  -->

    < BuildTasks.LabelInVSS

      DatabasePath = " $(VSSDatabasePath) "

      FilePathInVSS = " $ "

      Label = " Revision $(BuildNumber) "

   />

    < Message Text = " ------ CHECKING IN CHANGED FILES... DONE " Importance = " high " />

    < OnError ExecuteTargets = " ErrorOnCheckIn " />

  </ Target >

  <!-- ======================================================================================== -->

  < Target Name = " RecoverFromError " >

    < Message Text = " An error has occurred, reversing checkouts " />

    < BuildTasks.UndoCheckOutFromVSS

      DatabasePath = " $(VSSDatabasePath) " IgnoreError = " true "

      FilePathInVSS = " $/Some/Path/Here/LP/AssemblyInfo.cs "

      WorkingDirectory = " LP "

   />

    < BuildTasks.UndoCheckOutFromVSS

      DatabasePath = " $(VSSDatabasePath) " IgnoreError = " true "

      FilePathInVSS = " $/Some/Path/Here/LP/BuildNumberLP.txt "

      WorkingDirectory = " LP "

   />

    < BuildTasks.UndoCheckOutFromVSS

    DatabasePath = " $(VSSDatabasePath) " IgnoreError = " true "

    FilePathInVSS = " $/Some/Path/Here/DatabaseScripts/DatabasePackages.sql "

    WorkingDirectory = " LP/DatabaseScripts "

   />

    < BuildTasks.UndoCheckOutFromVSS

      DatabasePath = " $(VSSDatabasePath) " IgnoreError = " true "

      FilePathInVSS = " $/Some/Path/Here/LPinstaller/Properties/AssemblyInfo.cs "

      WorkingDirectory = " LPinstaller/Properties "

   />

    < BuildTasks.UndoCheckOutFromVSS

      DatabasePath = " $(VSSDatabasePath) " IgnoreError = " true "

      FilePathInVSS = " $/Some/Path/Here/Release/LPSetup.msi "

      WorkingDirectory = " LPSetup/Release "

   />

    < BuildTasks.UndoCheckOutFromVSS

      DatabasePath = " $(VSSDatabasePath) " IgnoreError = " true "

      FilePathInVSS = " $/Some/Path/Here/Release/setup.exe "

      WorkingDirectory = " LPSetup/Release "

   />

  </ Target >

  <!-- ======================================================================================== -->

  < Target Name = " ErrorOnCheckIn " >

    <!-- ****************************************

    Does this actually show a message box? If so you should place a condition on this task

    usage here to make sure that this can be disabled so that the builds can be automated.

    **************************************** -->

    < BuildTasks.ShowMessageBox Message =

        " Build process failed to check in the files for the new build or reverse checkouts.

        Make sure that all files are checked in and retry the build. " />

  </ Target >

</ Project >

 

Sayed Ibrahim Hashimi

Wednesday, June 03, 2009 4:25:21 AM (GMT Daylight Time, UTC+01:00)  #    Comments [0]  | 

When I was in Orlando presenting at the Orlando Code Camp I had the pleasure of working with Russ Fustino and Stan Schultes on the latest edition of Russ' Toolshed - It's All About the Tools. This is a Channel 9 show that Russ has created. You can check out the video that I'm in at Episode 2 It's All About The Tools TV Show.

The topic that I discuss in that video is how you can create a custom MSBuild logger to update your Twitter page to keep everybody informed about the build. I love how using a REST based api can be so simple when appropriate. Since Twitter exposes one, of course it was pretty simple. I think that this is a pretty cool application of a custom MSBuild logger, and as far as I know it is the first of it's kind. You can download the source for my logger from my company's page sedotech.com and clicking on the MSBuild Twitter Logger link there.

Check me out in that video, I'm presenting from about the 50 minute mark to about the 65 minute mark. The guys were teasing me saying that I type fast, I don't think so, do you?

 

This is my second video on Channel 9, my first is described in my post at http://www.sedodream.com/PermaLink,guid,4db4f0b7-9d23-4c64-9fd1-992fb2ae1727.aspx.

Sayed Ibrahim Hashimi

Wednesday, June 03, 2009 4:25:11 AM (GMT Daylight Time, UTC+01:00)  #    Comments [0]  | 
Tuesday, June 02, 2009

This coming Wednesday I will be at the Jacksonville Developer User Group. The topic title is "Leveraging Web Deployment Projects". I am still thinking about a new title, I'm not extremely happy about that one. Here is the description about the talk.

In this session we will take a look at how Web Deployment Projects can be used to assist in the deployment of web sites and web applications; including ASP.NET Web Applications and ASP.NET MVC Web Applications. We will give an overview of what Web Deployment Projects are and the functionality that is available out of the box. A Web Deployment Project is a wrapper for the aspnet_compiler.exe tool in the form of an MSBuild project and adds value to using the tool itself. Because they are MSBuild files we are able to customize and extend the process. We will discuss how we can customize the process to perform common steps such as

  1. Creating Virtual Directories
  2. Updating values in the web.config file
  3. Encrypting the web.config file
  4. Minimizing JavaScript files
  5. Versioning the Assemblies

In this session we will not be covering MSBuild itself, so I will not go into too much detail about MSBuild specifics. More to be discussed is how you can take advantage of Web Deployment Projects and how that build process can be extended and customized.

 

Sayed Ibrahim Hashimi

Tuesday, June 02, 2009 4:25:06 AM (GMT Daylight Time, UTC+01:00)  #    Comments [0]  | 
Tuesday, May 26, 2009

Before I begin this post I must say that I do not have any inside information about the release of Visual Studio 2010 or .NET 4. The post is composed of 100 % speculation and based on information that has already been made publicly available.

I am pretty interested to know the release date for Visual Studio 2010, and .NET Framework 4.0, so I asked around but no one could tell me anything. So I decided to do some research as to the release dates for Visual Studio 2005 and Visual Studio 2008 based on the release of their Beta releases. I came up with the following table.

 

Beta 1

Beta 2

RTM

Beta 1 - Beta 2

Beta 2 - RTM

Visual Studio 2005

06/29/2004

04/18/2005

11/07/2005

43 Weeks

29 Weeks

Visual Studio 2008

04/19/2007

07/26/2007

11/19/2007

14 Weeks

17 Weeks

Visual Studio 2010

05/18/2009

11/30/2009

05/09/2010

28 Weeks

20 Weeks

Yellow cells are 100% based just on the averages of the two previous versions

 

When Visual Studio 2005 came out there were huge changes. I think this is why the amount of time between Beta 1 and Beta 2, and between Beta 2 and RTM were so much longer then their corresponding periods in Visual Studio 2008. I think for the release of Visual Studio 2010 we are going to be somewhere between the two time periods. So maybe a decent indicator would simply be the average of the two. This is what I used to come up with the cells that are shaded in yellow. I'm sure this will be off but hopefully by weeks and not months!

   

Sayed Ibrahim Hashimi

Tuesday, May 26, 2009 4:24:49 AM (GMT Daylight Time, UTC+01:00)  #    Comments [0]  | 
Monday, May 18, 2009

If you are using the ASP.NET MVC DefaultModelBinder to manage the creating complex types from your views’ form data, as well as the validation summary helper provided with ASP.NET MVC then you may have run into the situation I did. I created a simple form, in a dummy app,  to create a new contact. The page is named AddContactClassic.aspx, the contents are shown below.

<% @ Page Title ="" Language ="C#" MasterPageFile ="~/Views/Shared/Site.Master" Inherits ="System.Web.Mvc.ViewPage" %>

 

<% @ Import Namespace ="Sedodream.Web.Common.Contact" %>

 

< asp : Content ID ="Content1" ContentPlaceHolderID ="TitleContent" runat ="server">

      Add Contact Classic

</ asp : Content >

 

< asp : Content ID ="Content2" ContentPlaceHolderID ="MainContent" runat ="server">

    < h2 > Add Contact Classic </ h2 >

   

    <% = Html.ValidationSummary( "Errors exist" ) %>

   

    < ol >< li >< span class ="success-message"> <% = ViewData[ "SuccessMessage" ]%> </ span ></ li ></ ol >

    <% using (Html.BeginForm())

       { %>

    < fieldset >

        < legend > Account Information </ legend >

        < ol >

            < li >

                < label for ="FirstName"> First name </ label >

                <% = Html.TextBox( "FirstName" ) %>

                <% = Html.ValidationMessage( "FirstName" , "*" ) %>

            </ li >

            < li >

                < label for ="LastName"> Last name </ label >

                <% = Html.TextBox( "LastName" ) %>

                <% = Html.ValidationMessage( "LastName" , "*" ) %>

            </ li >

            < li >

                < label for ="Email"> Email </ label >

                <% = Html.TextBox( "Email" )%>

                <% = Html.ValidationMessage( "Email" , "*" )%>

            </ li >

            < li >

                < label for ="Phone"> Phone </ label >

                <% = Html.TextBox( "Phone" )%>

                <% = Html.ValidationMessage( "Phone" , "*" )%>

            </ li >

            < li >

                < div class ="option-group" id ="Gender">

                    <% = Html.RadioButton( "Gender" , Gender .Male.ToString())%> < span > <% = Gender .Male.ToString() %> </ span >

                    <% = Html.RadioButton( "Gender" , Gender .Female.ToString())%> < span > <% = Gender .Female.ToString() %> </ span >

                </ div >

            </ li >            

            < li >

                < input type ="submit" value ="Add contact" />

            </ li >

        </ ol >

    </ fieldset >

    <% } %>

 

</ asp : Content >

In my ContactController class the following methods are defined.

public ActionResult AddContactClassic()

{

    return View();

}

[ AcceptVerbs ( HttpVerbs .Post)]

public ActionResult AddContactClassic( Contact contact)

{

    if (contact == null ) { throw new ArgumentNullException ( "contact" ); }

 

    InternalAddContact(contact);

 

    return View();

}

When I ran the app and filled in all the values on the AddContactClassic page I was a bit surprised to see an error simply stating “A value is required.” Here is a screen shot.

So I assumed that I must have misspelled one of the names of the fields that were passed to the Html.TextBox method. Obviously this was not the issue, so then I remembered that the Contact class that I defined had another property, Id, which I was not contained in a field on the form. This is the case because this page is supposed to create a new Contact, so its Id will not be set. I changed the AddContactClassic(Contact) method to ignore the Id property when binding was occurring. Here is the new method.

[ AcceptVerbs ( HttpVerbs .Post)]

public ActionResult AddContactClassic( [ Bind (Exclude= "Id" )] Contact contact)

{

    if (contact == null ) { throw new ArgumentNullException ( "contact" ); }

 

    InternalAddContact(contact);

 

    return View();

}

By using the Bind attribute I was able to let the DefaultModelBinder know that I was not interested in getting the value for that field. Once I made this change everything worked fine.

In the Contact class I had incorrectly defined the Id property to be Guid instead of Guid? which is better. If I had correctly declared that then the DefaultModelBinder   would have known that it was not a required field and it would not have complained. But if you are using the Entity Framework , you may still have this issue anyway because it does not always create nullable fields for all nullable columns in my experience. Even after changing the Contact class to use Guid? I have purposefully left the Bind(Exclude=”Id”) on the method in case something changes in the implementation of the Contact class.

Sayed Ibrahim Hashimi

Monday, May 18, 2009 4:25:27 AM (GMT Daylight Time, UTC+01:00)  #    Comments [2]  | 

If you are using the ASP.NET MVC DefaultModelBinder to manage the creating complex types from your views' form data, as well as the validation summary helper provided with ASP.NET MVC then you may have run into the situation I did. I created a simple form, in a dummy app, to create a new contact. The page is named AddContactClassic.aspx, the contents are shown below.

<% @ Page Title ="" Language ="C#" MasterPageFile ="~/Views/Shared/Site.Master" Inherits ="System.Web.Mvc.ViewPage" %>

 

<% @ Import Namespace ="Sedodream.Web.Common.Contact" %>

 

< asp : Content ID ="Content1" ContentPlaceHolderID ="TitleContent" runat ="server">

      Add Contact Classic

</ asp : Content >

 

< asp : Content ID ="Content2" ContentPlaceHolderID ="MainContent" runat ="server">

    < h2 > Add Contact Classic </ h2 >

   

    <% = Html.ValidationSummary( "Errors exist" ) %>

   

    < ol >< li >< span class ="success-message"> <% = ViewData[ "SuccessMessage" ]%> </ span ></ li ></ ol >

    <% using (Html.BeginForm())

       { %>

    < fieldset >

        < legend > Account Information </ legend >

        < ol >

            < li >

                < label for ="FirstName"> First name </ label >

                <% = Html.TextBox( "FirstName" ) %>

                <% = Html.ValidationMessage( "FirstName" , "*" ) %>

            </ li >

            < li >

                < label for ="LastName"> Last name </ label >

                <% = Html.TextBox( "LastName" ) %>

                <% = Html.ValidationMessage( "LastName" , "*" ) %>

            </ li >

            < li >

                < label for ="Email"> Email </ label >

                <% = Html.TextBox( "Email" )%>

                <% = Html.ValidationMessage( "Email" , "*" )%>

            </ li >

            < li >

                < label for ="Phone"> Phone </ label >

                <% = Html.TextBox( "Phone" )%>

                <% = Html.ValidationMessage( "Phone" , "*" )%>

            </ li >

            < li >

                < div class ="option-group" id ="Gender">

                    <% = Html.RadioButton( "Gender" , Gender .Male.ToString())%> < span > <% = Gender .Male.ToString() %> </ span >

                    <% = Html.RadioButton( "Gender" , Gender .Female.ToString())%> < span > <% = Gender .Female.ToString() %> </ span >

                </ div >

            </ li >            

            < li >

                < input type ="submit" value ="Add contact" />

            </ li >

        </ ol >

    </ fieldset >

    <% } %>

 

</ asp : Content >

In my ContactController class the following methods are defined.

public ActionResult AddContactClassic()

{

    return View();

}

[ AcceptVerbs ( HttpVerbs .Post)]

public ActionResult AddContactClassic( Contact contact)

{

    if (contact == null ) { throw new ArgumentNullException ( "contact" ); }

 

    InternalAddContact(contact);

 

    return View();

}

When I ran the app and filled in all the values on the AddContactClassic page I was a bit surprised to see an error simply stating "A value is required." Here is a screen shot.

So I assumed that I must have misspelled one of the names of the fields that were passed to the Html.TextBox method. Obviously this was not the issue, so then I remembered that the Contact class that I defined had another property, Id, which I was not contained in a field on the form. This is the case because this page is supposed to create a new Contact, so its Id will not be set. I changed the AddContactClassic(Contact) method to ignore the Id property when binding was occurring. Here is the new method.

[ AcceptVerbs ( HttpVerbs .Post)]

public ActionResult AddContactClassic( [ Bind (Exclude= "Id" )] Contact contact)

{

    if (contact == null ) { throw new ArgumentNullException ( "contact" ); }

 

    InternalAddContact(contact);

 

    return View();

}

By using the Bind attribute I was able to let the DefaultModelBinder know that I was not interested in getting the value for that field. Once I made this change everything worked fine.

In the Contact class I had incorrectly defined the Id property to be Guid instead of Guid? which is better. If I had correctly declared that then the DefaultModelBinder would have known that it was not a required field and it would not have complained. But if you are using the Entity Framework, you may still have this issue anyway because it does not always create nullable fields for all nullable columns in my experience. Even after changing the Contact class to use Guid? I have purposefully left the Bind(Exclude="Id") on the method in case something changes in the implementation of the Contact class.

Sayed Ibrahim Hashimi

Monday, May 18, 2009 4:24:19 AM (GMT Daylight Time, UTC+01:00)  #    Comments [0]  | 
Thursday, May 14, 2009

A little while ago I received an email from a reader in which he provided a sample MSBuild script. Here were some comments that I sent him.

“One thing that I did notice that may be problematic in your MyBranchTool.common.targets is the following item group.

<ItemGroup>

    <MyTargetFiles Include="$(ProjectDir)$(OutDir)*" />

</ItemGroup>

Here you are declaring an item (outside of a target) which pickups files inside the OutDir. This may include files that were created (or moved there) during the build process.Items and properties declared outside of targets are evaluated before any target executes. What this means is that your MyTargetFiles item may not include all the files that it should. Instead you should put this decclaration inside of a target right before it is needed (which should be after the files have been placed inside the OutDir folder). Unless you are intentionally wanting to pick up the files in that folder before the build starts. If you have my book there is a section on Property & Item Evaluation take a look at that. I think it is somewhere near page 60 or so.”

Also if you are using MSBuild 3.5 you should specify the ToolsVersion on the Project element.”

Here is his response

“Ah, yes thanks for that! I was getting errors sometimes and I thought it was something like that but I didn’t know how to fix it - some files would be deleted by the Rebuild but not recreated, and then the Copy fails because those files are missing.

I have ordered your book, hopefully it arrives soon :) I look forward to reading through it!

Thanks again”

His initial question was not related to the issue that I commented on here. This happened to surface because he sent me his build script. I didn’t have the script that actually used that item, but I recognized that an item was being created from the $(OutDir) in a static item, which is a red flag for a problem ! Like I stated to him since files are placed into the OutDir folder at build time the item should be dynamic and not static. You should look for this in your build scripts as you edit them and make sure that they do not repeat this.

 

Sayed Ibrahim Hashimi

Thursday, May 14, 2009 3:59:35 AM (GMT Daylight Time, UTC+01:00)  #    Comments [0]  | 

Theme design by Jelle Druyts