Wednesday, February 29, 2012

Generate type safe classes for sharepoint - vol2

I created a T4 template file that will:
1 - Search for SharePoint content types.
2 - Generate type safe Names and ID's for them.

<#@ template debug="false" hostspecific="true" language="C#" #>
<#@ output extension=".cs" #>
<#@ assembly name="EnvDTE" #>
<#@ assembly name="System.Xml" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.IO" #>
<#@ import namespace="System.Xml" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Collections.Generic" #>
<# 
// GET fileNamespace -> http://lennybacon.com/CommentView,guid,6ba5f768-6325-4f09-8341-201122804f52.aspx
var hostServiceProvider = (IServiceProvider)Host;
var dte = (EnvDTE.DTE)hostServiceProvider.GetService(typeof(EnvDTE.DTE));
var activeSolutionProjects = (Array)dte.ActiveSolutionProjects;
var dteProject = (EnvDTE.Project)activeSolutionProjects.GetValue(0);
var defaultNamespace = dteProject.Properties.Item("DefaultNamespace").Value;
var templateDir = Path.GetDirectoryName(Host.TemplateFile);
var fullPath = dteProject.Properties.Item("FullPath").Value.ToString();
fullPath = fullPath.EndsWith("\\") ? fullPath.Substring(0, fullPath.Length-1) : fullPath;
var subNamespace = templateDir.Replace(fullPath, string.Empty).Replace("\\", ".");
var fileNamespace = string.Concat(defaultNamespace, subNamespace);

// GET All XML files -> http://weblogs.asp.net/lhunt/pages/CSharp-Coding-Standards-document.aspx
var searchPath = new DirectoryInfo(fullPath).Parent.FullName;
var folderList = new Stack<string>();
var allXmlFiles = new List<string>();
string[] currentFolders = null;
string[] currentFiles = null;
string thisFolder = null;
folderList.Push(searchPath);
while(folderList.Count > 0)
{
    thisFolder = folderList.Pop();
    currentFiles = Directory.GetFiles(thisFolder, "*.xml");
    foreach(string file in currentFiles) if (!file.Contains("\\Debug\\")) allXmlFiles.Add(file);      
    currentFolders = Directory.GetDirectories(thisFolder);
    if(currentFolders != null && currentFolders.Length > 0) foreach(string folder in currentFolders) folderList.Push(folder);    
}

// GET All Fields from XML files
var fields = new List<KeyValuePair<string, KeyValuePair<string, KeyValuePair<string, string>>>>();
foreach (string xmlFile in allXmlFiles)
{
 var doc = new XmlDocument();
    doc.Load(xmlFile);
    XmlElement root = doc.DocumentElement;
    foreach (XmlNode node in root.ChildNodes)
        if (node.Name == "ContentType" && node.Attributes != null)
  {
            var attributeName = node.Attributes["Name"];
            var attributeID = node.Attributes["ID"];
            var attributeDisplayName = node.Attributes["Description"];
   fields.Add(new KeyValuePair<string, KeyValuePair<string, KeyValuePair<string, string>>>((attributeName != null) ? attributeName.InnerText.Replace(" ", string.Empty).Replace(
                                            "-", string.Empty) : "",new KeyValuePair<string, KeyValuePair<string, string>>(xmlFile.Replace(searchPath + "\\",""), new KeyValuePair<string, string>((attributeID != null) ? attributeID.InnerText : "",(attributeDisplayName != null) ? attributeDisplayName.InnerText : ""))));
  }
}
#>// --------------------------------------------------------------------------------------------------------------------
// <copyright file="ContentTypes.cs" company="Imtech ICT Integrated Solutions">
//   Copyright 2012 by Imtech ICT Integrated Solutions. All rights reserved. This material may not be duplicated for any profit-driven enterprise.
// </copyright>
// <summary>
//   Static ContentType Names And Ids
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace <#= fileNamespace #>
{
    using Microsoft.SharePoint;

    /// <summary>
    /// Static ContentTypeNames
    /// </summary>
    public static partial class ContentTypeNames
    {
<#
string previousFile = "";
bool firstTimeRun = true;
foreach (var field in fields.OrderBy(t => t.Value.Key).ThenBy(t => t.Key))
{
 if (previousFile != field.Value.Key)
 { if (!firstTimeRun)
  { #>

<# }
  if (firstTimeRun){firstTimeRun = false;} #>
        // <#= field.Value.Key #>
<#   previousFile = field.Value.Key;
 } #>
        public static readonly string <#= field.Key #> = "<#= field.Key #>";
<#}#>
    }

    /// <summary>
    /// Static ContentTypeIds
    /// </summary>
    public static partial class ContentTypeIds
    {
<#
previousFile = "";
firstTimeRun = true;
foreach (var field in fields.OrderBy(t => t.Value.Key).ThenBy(t => t.Key))
{
 if (previousFile != field.Value.Key)
 { if (!firstTimeRun)
  { #>

<# }
  if (firstTimeRun){firstTimeRun = false;} #>
        // <#= field.Value.Key #>
<#   previousFile = field.Value.Key;
 } #>
        public static readonly SPContentTypeId <#= field.Key #> = new SPContentTypeId("<#= field.Value.Value.Key #>");
<#  } #>
    }
}

Generate type safe classes for sharepoint - vol1

I created a T4 template file that will:
1 - Search for SharePoint fields.
2 - Generate type safe FieldNames and ID's for them.


<#@ template debug="false" hostspecific="true" language="C#" #>
<#@ output extension=".cs" #>
<#@ assembly name="EnvDTE" #>
<#@ assembly name="System.Xml" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.IO" #>
<#@ import namespace="System.Xml" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Collections.Generic" #>
<# // GET fileNamespace -> http://lennybacon.com/CommentView,guid,6ba5f768-6325-4f09-8341-201122804f52.aspx
var hostServiceProvider = (IServiceProvider)Host;
var dte = (EnvDTE.DTE)hostServiceProvider.GetService(typeof(EnvDTE.DTE));
var activeSolutionProjects = (Array)dte.ActiveSolutionProjects;
var dteProject = (EnvDTE.Project)activeSolutionProjects.GetValue(0);
var defaultNamespace = dteProject.Properties.Item("DefaultNamespace").Value;
var templateDir = Path.GetDirectoryName(Host.TemplateFile);
var fullPath = dteProject.Properties.Item("FullPath").Value.ToString();
fullPath = fullPath.EndsWith("\\") ? fullPath.Substring(0, fullPath.Length-1) : fullPath;
var subNamespace = templateDir.Replace(fullPath, string.Empty).Replace("\\", ".");
var fileNamespace = string.Concat(defaultNamespace, subNamespace);
// END GET fileNamespace

// GET All Fields from XML files -> http://weblogs.asp.net/lhunt/pages/CSharp-Coding-Standards-document.aspx
string searchPath = new DirectoryInfo(fullPath).Parent.FullName;
Stack<string> folderList = new Stack<string>();
List<string> allXmlFiles = new List<string>();
string[] currentFolders = null;
string[] currentFiles = null;
string thisFolder = null;
folderList.Push(searchPath);
while(folderList.Count > 0)
{
thisFolder = folderList.Pop();
currentFiles = Directory.GetFiles(thisFolder, "*.xml");
foreach(string file in currentFiles)
if (!file.Contains("\\Debug\\"))
allXmlFiles.Add(file);
currentFolders = Directory.GetDirectories(thisFolder);
if(currentFolders != null && currentFolders.Length > 0)
foreach(string folder in currentFolders)
folderList.Push(folder);
}
var fields = new List<KeyValuePair<string, KeyValuePair<string, KeyValuePair<string, string>>>>();
foreach (string xmlFile in allXmlFiles)
{
var doc = new XmlDocument();
doc.Load(xmlFile);
XmlElement root = doc.DocumentElement;
foreach (XmlNode node in root.ChildNodes)
if (node.Name == "Field" && node.Attributes != null)
{
var attributeName = node.Attributes["Name"];
var attributeID = node.Attributes["ID"];
var attributeDisplayName = node.Attributes["DisplayName"];
string fieldName = "";
string fieldId = "";
string fieldDisplayName = "";
if (attributeName != null) fieldName = attributeName.InnerText;
if (attributeID != null) fieldId = attributeID.InnerText;
if (attributeDisplayName != null) fieldDisplayName = attributeDisplayName.InnerText;
fields.Add(
new KeyValuePair<string, KeyValuePair<string, KeyValuePair<string, string>>>(
fieldName,
new KeyValuePair<string, KeyValuePair<string, string>>(
xmlFile.Replace(searchPath + "\\",""), new KeyValuePair<string, string>(fieldId, fieldDisplayName))));
}
}
// Get All SiteColumn Files
#>// --------------------------------------------------------------------------------------------------------------------
// <copyright file="Fields.cs" company="Imtech ICT Integrated Solutions">
// Copyright 2012 by Imtech ICT Integrated Solutions. All rights reserved. This material may not be duplicated for any profit-driven enterprise.
// </copyright>
// <summary>
// Static Field Names And Ids
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace <#= fileNamespace #>
{
using System;

/// <summary>
/// Static FieldNames
/// </summary>
public static partial class FieldNames
{
<#
string previousFile = "";
foreach (var field in fields.OrderBy(t => t.Value.Key).ThenBy(t => t.Key))
{
if (previousFile != field.Value.Key)
{ #>

// <#= field.Value.Key #>
<# previousFile = field.Value.Key;
} #>
public static readonly string <#= field.Key #> = "<#= field.Key #>";
<#}#>
}

/// <summary>
/// Static FieldIds
/// </summary>
public static partial class FieldIds
{
<#
foreach (var field in fields.OrderBy(t => t.Value.Key).ThenBy(t => t.Key))
{
if (previousFile != field.Value.Key)
{ #>

// <#= field.Value.Key #>
<# previousFile = field.Value.Key;
} #>
public static readonly Guid <#= field.Key #> = new Guid("<#= field.Value.Value.Key #>");
<# } #>
}
}


This will create code like:



// --------------------------------------------------------------------------------------------------------------------
// <copyright file="Fields.cs" company="Imtech ICT Integrated Solutions">
// Copyright 2012 by Imtech ICT Integrated Solutions. All rights reserved. This material may not be duplicated for any profit-driven enterprise.
// </copyright>
// <summary>
// Static Field Names And Ids
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace ZP.Intranet.Helpers
{
using System;

/// <summary>
/// Static FieldNames
/// </summary>
public static partial class FieldNames
{

// Intranet\Content\SiteColumns\SiteColumns\Elements.xml
public static readonly string ColumnAuthor = "ColumnAuthor";
public static readonly string DocumentDescription = "DocumentDescription";
public static readonly string DocumentThema = "DocumentThema";
public static readonly string DocumentThemaTaxHTField0 = "DocumentThemaTaxHTField0";
public static readonly string FAQAntwoord = "FAQAntwoord";
public static readonly string GoogleMapsUrl = "GoogleMapsUrl";
public static readonly string isSticky = "isSticky";
public static readonly string JobTitle2 = "JobTitle2";
public static readonly string ListIndex = "ListIndex";
public static readonly string NewsExpirationDate = "NewsExpirationDate";
public static readonly string PublishingPageIntro = "PublishingPageIntro";
public static readonly string RouteContactDescription = "RouteContactDescription";
public static readonly string StickyExpirationDate = "StickyExpirationDate";
public static readonly string SummaryLinks1 = "SummaryLinks1";
public static readonly string WijzigingenTonen = "WijzigingenTonen";
public static readonly string Workingdays = "Workingdays";
public static readonly string ZMobiel = "ZMobiel";
public static readonly string ZPFax = "ZPFax";
public static readonly string ZPPicture = "ZPPicture";
public static readonly string ZPSecretariaat = "ZPSecretariaat";
public static readonly string ZPTelefoon = "ZPTelefoon";

// Kwaliteit\Content\SiteColumns\SiteColumns\Elements.xml
public static readonly string DocumentEigenaar = "DocumentEigenaar";
public static readonly string DocumentVersie = "DocumentVersie";
public static readonly string EvaluatieDatum = "EvaluatieDatum";
public static readonly string EvaluatieDatumVoorstel = "EvaluatieDatumVoorstel";
public static readonly string EvaluatieResultaat = "EvaluatieResultaat";
public static readonly string EvaluatieStatus = "EvaluatieStatus";
public static readonly string GewijzigdToelichting = "GewijzigdToelichting";
public static readonly string KwaliteitThema = "KwaliteitThema";
public static readonly string KwaliteitThemaTaxHTField0 = "KwaliteitThemaTaxHTField0";
public static readonly string Reactie = "Reactie";
public static readonly string ReactiePersoon = "ReactiePersoon";
public static readonly string RedenAfkeur = "RedenAfkeur";
public static readonly string RedenUitstel = "RedenUitstel";
public static readonly string Uitstel = "Uitstel";
}

/// <summary>
/// Static FieldIds
/// </summary>
public static partial class FieldIds
{

// Intranet\Content\SiteColumns\SiteColumns\Elements.xml
public static readonly Guid ColumnAuthor = new Guid("{8fed943f-9baf-44fe-b7c6-623abadabd42}");
public static readonly Guid DocumentDescription = new Guid("{1828f1f6-35fb-4795-92c9-477dcd54a921}");
public static readonly Guid DocumentThema = new Guid("{cd323e0e-665a-4709-81dc-5746d741e492}");
public static readonly Guid DocumentThemaTaxHTField0 = new Guid("{a3e9d854-9997-449a-97f3-8d7066bab16f}");
public static readonly Guid FAQAntwoord = new Guid("{bf170ac7-397c-4d58-97a3-6918d4c3b340}");
public static readonly Guid GoogleMapsUrl = new Guid("{863efa7c-a265-452e-97a2-52836ffbfa82}");
public static readonly Guid isSticky = new Guid("{88f5eeb8-ec0c-419b-9c30-c4c3295e5547}");
public static readonly Guid JobTitle2 = new Guid("{2ace342a-be43-4412-92c0-504cc73f2675}");
public static readonly Guid ListIndex = new Guid("{0cbd1771-2b6e-4f68-93ea-70f9bb2c16ca}");
public static readonly Guid NewsExpirationDate = new Guid("{0fe49e6f-e953-410b-99f5-44cfc71bd393}");
public static readonly Guid PublishingPageIntro = new Guid("{1b72fc77-3add-486c-869c-5c71c25a4c77}");
public static readonly Guid RouteContactDescription = new Guid("{4c9f4081-adbf-40c2-9cb7-ff464463b6d4}");
public static readonly Guid StickyExpirationDate = new Guid("{fbae95fc-0e10-47bc-8ef1-2cf61a417d12}");
public static readonly Guid SummaryLinks1 = new Guid("{3b4e0c4d-6dea-49c9-b80d-b536d301817a}");
public static readonly Guid WijzigingenTonen = new Guid("{1ec13dcd-adbd-485b-91ab-d703e7ce3ebc}");
public static readonly Guid Workingdays = new Guid("{65a02752-d6fe-4806-9813-f48f23e47cc8}");
public static readonly Guid ZMobiel = new Guid("{7e10bf64-6f59-4f01-b5e9-df6e63da3dc7}");
public static readonly Guid ZPFax = new Guid("{1dfd705e-77eb-4c06-9c81-7464b90df58e}");
public static readonly Guid ZPPicture = new Guid("{57bf7368-a9f4-4fc4-a746-b20ab49dc81c}");
public static readonly Guid ZPSecretariaat = new Guid("{8a797061-3daa-45a1-8d12-8f122ba5be57}");
public static readonly Guid ZPTelefoon = new Guid("{ca259e0c-055a-41e5-82f4-1705b4884c45}");

// Kwaliteit\Content\SiteColumns\SiteColumns\Elements.xml
public static readonly Guid DocumentEigenaar = new Guid("{4dd34746-7b40-4235-99a7-06cfec789291}");
public static readonly Guid DocumentVersie = new Guid("{e457c652-b3d7-4301-b485-e709256c2dd2}");
public static readonly Guid EvaluatieDatum = new Guid("{814e7328-1ede-42e6-8c36-49b852ca99ed}");
public static readonly Guid EvaluatieDatumVoorstel = new Guid("{c2c3cb23-dc2c-45e0-ac35-8ba706601f71}");
public static readonly Guid EvaluatieResultaat = new Guid("{84145504-5e19-4ffd-b023-d8b44562ae6a}");
public static readonly Guid EvaluatieStatus = new Guid("{9355964F-EA27-4CB4-ACD6-083E6E8165B1}");
public static readonly Guid GewijzigdToelichting = new Guid("{bd1743f0-6af7-4211-a340-50c0fa883f54}");
public static readonly Guid KwaliteitThema = new Guid("{2efce8ed-eb88-4afb-b3d7-ba01db53f0b4}");
public static readonly Guid KwaliteitThemaTaxHTField0 = new Guid("{c32bb43b-54f7-4e08-a169-cdec83885bbb}");
public static readonly Guid Reactie = new Guid("{9e89ed0d-bc55-4d3b-a908-568a93925327}");
public static readonly Guid ReactiePersoon = new Guid("{11189fed-e050-4317-8d67-0a5b90f48073}");
public static readonly Guid RedenAfkeur = new Guid("{21486E8F-A1E9-4104-AFD7-2871599C058B}");
public static readonly Guid RedenUitstel = new Guid("{4e331dd7-51ab-4a35-b996-7b8617bfa4c2}");
public static readonly Guid Uitstel = new Guid("{084d857a-546d-41bc-b95b-a535c375524e}");
}
}

Saturday, February 4, 2012

Manipulating query string, the type safe way!

Our goal for today: Safe some valuable time.

Everyone who is developing for the web will come across the use of query string parameters.

SNAGHTML1a40b7f2

Handling these little buggers has proven to be quite time consuming.
Say we have: ../Default.aspx?PageNumber=1
Methods like Page.Request.QueryString[] are far from intuitive:

The old way:

public partial class _Default : Page
{
protected void Page_Load(object sender, EventArgs e)
{
int pageNumber;
const string qsParam = "PageNumber";
object qsObject = Page.Request.QueryString[qsParam];
if (qsObject != null)
{
int qsValue;
if (int.TryParse(qsObject.ToString(), out qsValue))
pageNumber = qsValue;
else
pageNumber = -1;
}
else
pageNumber = -1;
}
}

The better way:

public partial class _Default : Page
{
protected void Page_Load(object sender, EventArgs e)
{
var queryString = new QueryStringParam();
int pageNumber = queryString.PageNumber ?? -1;
}
}

public class QueryStringParam : QueryStringParser
{
public int? PageNumber;
}

Source code of QueryStringParser:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Collections.Specialized;
using System.Web;
using System.Reflection;

namespace Helpers
{
public abstract class QueryStringParser
{
private NameValueCollection _queryString;

private FieldInfo[] _fields;
private IEnumerable<FieldInfo> Fields
{
get { return _fields ?? (_fields = GetType().GetFields()); }
}

protected QueryStringParser()
{
InitializeQueryString();
}

private void InitializeQueryString()
{
foreach (var fieldInfo in Fields) fieldInfo.SetValue(this, null);
_queryString = HttpUtility.ParseQueryString(HttpContext.Current.Request.Url.Query);
if (_queryString.Keys.Count > 0)
foreach (string key in _queryString.Keys)
{
var foundField = Fields.FirstOrDefault(cust => cust.Name == key);
if (foundField != null)
{
Object tempObject = null;
var value = _queryString[key];
var fieldType = foundField.FieldType;
try
{
if (fieldType == typeof(Guid?)) tempObject = new Guid(value);
if (fieldType == typeof(string)) tempObject = value;
if (fieldType == typeof(int?)) tempObject = int.Parse(value);
if (fieldType == typeof(bool?)) tempObject = bool.Parse(value);

// check for enum
var underlyingType = Nullable.GetUnderlyingType(fieldType);
if (underlyingType != null && underlyingType.IsEnum)
tempObject = Enum.Parse(underlyingType, value, true);

if (tempObject != null) foundField.SetValue(this, tempObject);
}
catch (Exception)
{
} // Can not convert querystring value into strongly typed parameter
}
}
}

public override string ToString()
{
foreach (var field in Fields)
{
var fieldValue = field.GetValue(this);
if (fieldValue != null)
_queryString[field.Name] = fieldValue.ToString();
else
_queryString.Remove(field.Name);
}
string returnValue = String.Format("?{0}", _queryString);
InitializeQueryString();
return returnValue;
}
}
public static class QueryStringParserExtensionMethods
{
public static bool HasValue(this string input)
{
return (!string.IsNullOrEmpty(input));
}
public static string Value(this string input)
{
return input;
}
}
}