Tuesday 30 November 2010

MSBuild and recursive copying

If you require to copy files and folder recursively, you'll need to use the following code.

First declare the list of files to copy in an ItemGroup

<ItemGroup>
  <Files Include=".\**\*.cs" />
</ItemGroup>

Then use the files metadata to perform the copy.

<copy DestinationFiles="@(Files)->'location\%(RecursiveDir)%(Filename)%(Extension)')" SourceFiles="@(Files)" />

More information available at MSBuild Team Blog article

MSBuild updating TeamCity build status

If you are using TeamCity and MSBuild to provide Continuous Integration and are using custom build tasks, you can get MSBuild to update the status of the build in TeamCity.

You need to add the following line:

<Message Importance="high" Text="##teamcity[progressMessage 'Packaging media files ...']" />

MSBuild calling same target multiple times

If you are doing similar tasks within a build, you can set-up a target and call it multiple times, like copying files between directories. You can pass in parameters like variables, to keep the methods as generic as possible.

An example:
<MsBuild Projects="$(MSBuildProjectFile)" Targets="MethodName" Properties="Param1=Value" />

<Target Name="MethodName">
<ItemGroup>
<Path Include="Source\$(Value)"/>
</ItemGroup>
...
</Target>

Friday 19 November 2010

Sitecore Treelist filtering

We have a treelist for selecting content to display as lists. The editor only needs to select the parent and not any of the children. Using the default source for a treelist to point to the containing folder you allow the editors to see all the children.

You could write a query like below to exclude or include the templates you require:
/sitecore/content/DisplayItems/descendant-or-self::*[@@templatename!='Template1' and @@templatename!='Template2' and @@templatename!='Template3']

This can be changed to use the following format which is easier to read and has more options.
Datasource=/sitecore/content/DisplayItems&ExcludeTemplatesForDisplay=Template1,Template2,Template3

Using this approach, there are several other parameters that you can set like:
  • IncludeTemplatesForSelection
  • ExcludeTemplatesForSelection
  • IncludeTemplatesForDisplay
  • ExcludeTemplatesForDisplay
There is more reading and options on this at LearnSitecore

Wednesday 10 November 2010

key not valid for use in specified state

Something that a colleague recently found out that may be useful if you ever need to use the RSA Encryption provider in the .Net Framework.

If you try to encrypt data that exceeds 245 bytes you get an error "key not valid for use in specified state". This is a little misleading considering the cause, which I found here in the end: http://social.msdn.microsoft.com/Forums/en-US/clr/thread/4e3ada0a-bcaf-4c67-bdef-a6b15f5bfdce/

For those of you interested you can re-create with the following (this is a modification to the RSA Example from http://msdn.microsoft.com/en-us/library/system.security.cryptography.rsacryptoserviceprovider.aspx).

If you uncomment the second 'Append' line and re-run it the provider fails with the "key not valid" exception.
using System;
using System.Security.Cryptography;
using System.Text;

class RSACSPSample
{

static void Main()
{
StringBuilder sb = new StringBuilder();
sb.Append("The quick brown fox jumped over the lazy dogs.");
//sb.Append("The quick brown fox jumped over the lazy dogs.");

Console.WriteLine(sb.Length.ToString());

try
{
//Create a UnicodeEncoder to convert between byte array and string.
UnicodeEncoding ByteConverter = new UnicodeEncoding();

//Create byte arrays to hold original, encrypted, and decrypted data.
byte[] dataToEncrypt = ByteConverter.GetBytes(sb.ToString());
byte[] encryptedData;
byte[] decryptedData;

//Create a new instance of RSACryptoServiceProvider to generate
//public and private key data.
using (RSACryptoServiceProvider RSA = new RSACryptoServiceProvider())
{

//Pass the data to ENCRYPT, the public key information
//(using RSACryptoServiceProvider.ExportParameters(false),
//and a boolean flag specifying no OAEP padding.
encryptedData = RSAEncrypt(dataToEncrypt, RSA.ExportParameters(false), false);

//Pass the data to DECRYPT, the private key information
//(using RSACryptoServiceProvider.ExportParameters(true),
//and a boolean flag specifying no OAEP padding.
decryptedData = RSADecrypt(encryptedData, RSA.ExportParameters(true), false);

//Display the decrypted plaintext to the console.
Console.WriteLine("Decrypted plaintext: {0}", ByteConverter.GetString(decryptedData));
}
}
catch (ArgumentNullException)
{
//Catch this exception in case the encryption did
//not succeed.
Console.WriteLine("Encryption failed.");

}

Console.ReadKey();
}

static public byte[] RSAEncrypt(byte[] DataToEncrypt, RSAParameters RSAKeyInfo, bool DoOAEPPadding)
{
try
{
byte[] encryptedData;
//Create a new instance of RSACryptoServiceProvider.
using (RSACryptoServiceProvider RSA = new RSACryptoServiceProvider())
{

//Import the RSA Key information. This only needs
//toinclude the public key information.
RSA.ImportParameters(RSAKeyInfo);

//Encrypt the passed byte array and specify OAEP padding.
//OAEP padding is only available on Microsoft Windows XP or
//later.
encryptedData = RSA.Encrypt(DataToEncrypt, DoOAEPPadding);
}
return encryptedData;
}
//Catch and display a CryptographicException
//to the console.
catch (CryptographicException e)
{
Console.WriteLine(e.Message);

return null;
}

}

static public byte[] RSADecrypt(byte[] DataToDecrypt, RSAParameters RSAKeyInfo, bool DoOAEPPadding)
{
try
{
byte[] decryptedData;
//Create a new instance of RSACryptoServiceProvider.
using (RSACryptoServiceProvider RSA = new RSACryptoServiceProvider())
{
//Import the RSA Key information. This needs
//to include the private key information.
RSA.ImportParameters(RSAKeyInfo);

//Decrypt the passed byte array and specify OAEP padding.
//OAEP padding is only available on Microsoft Windows XP or
//later.
decryptedData = RSA.Decrypt(DataToDecrypt, DoOAEPPadding);
}
return decryptedData;
}
//Catch and display a CryptographicException
//to the console.
catch (CryptographicException e)
{
Console.WriteLine(e.ToString());

return null;
}

}
}
You can force a key size in the constructor for the provider to allow more data, but this slows the algorithm down considerably.

Hopefully this may be useful to someone at some point :