Thursday, April 14, 2011

Publishing VS2010 Web Projects using command line

Since I started developing using Visual Studio 2010, I was impressed about WebDeploy integration into IDE. Particularly I was found one key publishing feature very useful for me:

image

Especially I use “File System” publish method. I was searching a way to execute this publish scenario from command prompt, maybe on machine without Visual Studio installed.

It took me a couple of hours of googling, but finally I found 2 blog posts that made me to complete the puzzle: Daniel Chambers post and Sayed Ibrahim Hashimi post.

Here is my working combination:

  1. Add {ProjectName}.wpp.targets file to Web app project folder (right aside of .csproj file), where {ProjectName} is the name of project (name of project file).
  2. Add new target to the file from #1. This target is responsible to copy site files to the specified destination:
       1: <?xml version="1.0" encoding="utf-8"?>
       2: <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
       3:    <Target Name="PublishToFileSystem" DependsOnTargets="PipelinePreDeployCopyAllFilesToOneFolder">
       4:     <Error Condition="'$(PublishDestination)'==''" Text="The PublishDestination property must be set to the intended publishing destination." />
       5:     <MakeDir Condition="!Exists($(PublishDestination))" Directories="$(PublishDestination)" />
       6:     
       7:     <ItemGroup>
       8:         <PublishFiles Include="$(_PackageTempDir)\**\*.*" />
       9:     </ItemGroup>
      10:  
      11:     <Copy SourceFiles="@(PublishFiles)" DestinationFiles="@(PublishFiles->'$(PublishDestination)\%(RecursiveDir)%(Filename)%(Extension)')" SkipUnchangedFiles="True" />
      12: </Target>
      13: </Project>
  3. Call new target defining actual parameters:
  4.    1: %windir%\Microsoft.NET\Framework\v4.0.30319\MSBuild Mvc.csproj /T:PublishToFileSystem /p:Configuration=Release;PublishDestination=C:\Sites\Mvc;AutoParameterizationWebConfigConnectionStrings=false

Please note last parameter ‘AutoParameterizationWebConfigConnectionStrings’. This parameter set to false in order to keep web.config file transformed according to build configuration BUT NOT tokenized.

Tuesday, February 8, 2011

Consuming IDataReader with LINQ.

Why?

  • IDataReader is a very efficient way to retrieve data from database. Since it’s forward-only, the data cannot be manipulated directly (in opposite to DataSet, which is disconnected data source).

  • LINQ (language-integrated query) is a new .NET approach to work with data in code. Very powerful, flexible and extendable.

Problem

LINQ is built on and relies on IEnumerable<T> interface, IDataReader does not implement this interface.

Solution

Extension method:

Code:
   1:  
   1:  public static class DataReaderExtension
   2:   {
   3:     public static IEnumerable<T> DataRecord<T>(this IDataReader source, Func<IDataRecord, T> objectBuilder)
   4:     {
   5:       if (source == null)
   6:         throw new ArgumentNullException("source");
   7:       while (source.Read())
   8:       {
   9:         yield return objectBuilder((IDataRecord) source);
  10:       }
  11:     }
  12:   }
Description:

Since this is extension method – it can be applied on each object implements IDataReader interface, for example db.ExecuteReader(dbCommand)).

Input:

Func<IDataRecord, T>  - this is actually strong type pointer to function that creates object of type T from reader row. You can read more about Generic Delegate Func here. .NET shipped with more predefined strong type delegates, as described here.

Output:

IEnumerable<T> – enumerable collection of elements that can be used as input to LINQ query.

Usage Example:
   1:  var res = db.ExecuteReader(dbCommand);
   2:  var result = res.DataRecord(rec => new LobbyGame
   3:        {
   4:             GameUrl = rec.GetString(rec.GetOrdinal("GameURL")),
   5:             Name = rec.GetString(rec.GetOrdinal("GameName")),
   6:             Id = rec.GetInt32(rec.GetOrdinal("GameID")),
   7:             Description = rec.GetString(rec.GetOrdinal("Description")),
   8:             ShortDescription = rec.GetString(rec.GetOrdinal("ShortDescription")),
   9:             SourceId = rec.GetInt32(rec.GetOrdinal("SourceID")),
  10:         });

In this example I create IDataReader on line 1, then on line 2 I use my extension method to create IEnumerable<LobbyGame>. Note that as input parameter to extension method I use lambda expression that defines creation of each LobbyGame instance.

del.icio.us Tags: ,