Wednesday, October 28, 2009

How to debug a Self-hosted WCF Service

After manually attaching the debugger to the hosting process to debug the code, I got this error when I try to debug a self-hosted WCF service:
System.ServiceModel.AddressAlreadyInUseException: The TransportManager failed to listen on the supplied URI using the NetTcpPortSharing service: the URI is already registered with the service.

As the self-hosted WCF Service (runs as a running process [Windows Service])] has used port number XXXX already, when Visual Studio attempts to fire the WCF Service Host again on the same port, the conflict occurs as the URI has been used up already.

Starting the Net.Tcp Port Sharing Service did not help either.

The work around to debug this issue in steps:
1.) Unload the project that contains the code for the host.
2.) Attach the process to the windows/self-hosting service. (At this point, WCF Service Host does not complain that the URI has been used as it attaches to the running self-hosting service instance)
3.) Reload the unloaded project and set breakpoints to step through code.

Tuesday, October 27, 2009

Unable to detect external usb hard drive on Windows Server 2003

I have been facing this issue with my external hard disk for quite some time.
Even though I manage to fix it in one way or the other every time, I just wanted to write it down this time so that it will be useful for some one else with the same problem (or may be me the next time).

I have a Maxtor Basics Portable USB External Drive (320 GB).
By default, no external drives are supported (nor very compatible in practice) in server operating systems such as Windows 2000 Server, Windows 2003 Server, or Windows 2008 Server.

So when a new USB Hard drive is connected, even though the hardware is recognized, I am not able to see the drive in the list of drives My Computer.

Open up "Computer Management" screen in Windows 2003 and go to "Disk Management" found under "Storage".



So its evident that the hard disk is recognized but Windows 2003 has not given it a drive letter. In order to get one, right click on the disk, click on "Change drive letters and paths". In the next screen, click on "Add" and give a drive letter as desired.



I am now able to see the new drive :)

Wednesday, October 21, 2009

Firing HttpModule on a file that does not exist physically

I am not going to explain what an HttpModule is and how to create one. There are hundreds of posts in Google that explain the same with nice screen shots.

This article here is a good example for some one who just started to learn about them

I knew that a HttpModule when configured properly has to intercept each and every request that reaches the web app it has been set on. But by default, the HttpModule fires only if the file exists on the server physically.

With a configuration change in IIS, I had been able to fire the HttpModule for every request irrespective of whether the file exists or not physically.

Step-1
Open up the properties of website and go to the tab "Home Directory"


Step-2
Click "Configuration", add a wildcard application map as shown below(aspnet_isapi.dll). Make sure that "Verify that file exists" is checked off

Debugging web based infopath forms

Recently a colleague who has been working on Infopath 2007 for quite long time has stated that its not possible to debug web-based infopath at all.

I believe that he came to that conclusion due to the fact that Visual Studio Tools for Applications (VSTA) does not show the option "Attach to debugger".

May be there are few others in the same boat as I was (I had been with the same opinion until my friend Sandeep Nahta said that web-based Infopath forms are very likely debuggable). After a bit of research, it has been evident that debugging web-based Infopath forms is not a big deal.

Follow the below steps:
1) Ensure the InfoPath Form Template is compiled in the Debug Configuration so the XSN includes the symbol (PDB) file. (From the Project menu choose Project Properties .Ensure the Configuration option is set to Active(Debug)/Debug)
2) Open the local copy of the code file (make sure not to open the csproj file created by Infopath. Just open the .cs file ONLY) in Visual Studio and set a breakpoint
3) Attach to the appropriate w3wp process
4) Execute the process that will cause the breakpoint to be hit

Ref: http://blogs.msdn.com/infopath/archive/2006/11/24/debugging-browser-forms.aspx

Monday, October 5, 2009

How to add web parts to publishing page layouts and make them available to all the pages through code?

Scenario:
How to add web parts to publishing page layouts and make them available to all the pages through code?

Explanation:
So whats the big deal? What is so special? This is the question that strikes in one's mind after reading the title of this post.

Well.. when custom web parts are added to publishing pages that are created from publishing page layouts, until the page is checked out, the web parts wont be displayed. (SharePoint thinks that the web parts are unsafe until the page is checked out for the first time even after strong naming them and marking them as safecontrols, etc..)

There are various ways to do this. Other than the one I am going to describe below, I have seen a project in which the web parts have been specified in the site definition thus marking the controls are safe.

To fix this issue, we have created a custom control that resides on the page layout which takes care of carrying out operations on page such as adding, deleting, moving and setting properties on web parts.

Code:
In the code-behind of the page layout add the pagelayout control in the OnInit() as below:
/// <summary>
/// Registers page layout control that adds web parts to the page.
/// </summary>
/// <param>Virtual path of XML File that contains web part information for the page</param>
/// <returns></returns>
protected void AddWebPartsToPage(String webpartsXMLFileUrl)
{
try
{
PageLayoutControl plc = new PageLayoutControl(webpartsXMLFileUrl);
this.Page.Controls.Add(plc);
}
catch (Exception exception)
{
if (ExceptionPolicy.HandleException(exception, "Iti Exception"))
{
}
}
}

Sample Xml that goes in the webpartsXMLFileUrl
<WebParts LastModified="9/5/2008">
<WebPartAction>
<action>Delete</action>
<typeName>WebPart1.WebPart</typeName>
<zoneIndex>0</zoneIndex>
</WebPartAction>
<WebPartAction>
<action>Delete</action>
<typeName>WebPart2.WebPart</typeName>
<zoneIndex>1</zoneIndex>
</WebPartAction>
<WebPartAction>
<assemblyName>WebPart1, Version=[Version], Culture=neutral, PublicKeyToken=[Token]</assemblyName>
<className>WebPart1.WebPart</className>
<zoneID>RightTop</zoneID>
<zoneIndex>0</zoneIndex>
<typeName></typeName>
<action>Add</action>
<Properties>
<!-- Properties for the web part go here -->
<!-- Example -->
<Property Key="Title" Type="string" Value="WebPart1 Title"/>
<Property Key="ChromeState" Type="PartChromeState" Value="Normal"/>
</Properties>
</WebPartAction>
<WebPartAction>
<assemblyName>WebPart2, Version=[Version], Culture=neutral, PublicKeyToken=[Token]</assemblyName>
<className>WebPart2.WebPart</className>
<zoneID>RightTop</zoneID>
<zoneIndex>1</zoneIndex>
<typeName></typeName>
<action>Add</action>
<Properties>
<!-- Properties for the web part go here -->
<Property Key="Title" Type="string" Value="WebPart1 Title"/>
<Property Key="ChromeState" Type="PartChromeState" Value="Normal"/>
</Properties>
</WebPartAction>
</WebParts>

And finally the PageLayoutControl code:
using System;
using System.Collections.Generic;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using Microsoft.SharePoint;
using Microsoft.SharePoint.WebPartPages;
using System.Xml;
using System.Xml.Serialization;
using System.Xml.Schema;
using System.Diagnostics;
using Microsoft.SharePoint.Portal.WebControls;
using System.Collections;
using System.Reflection;
using System.ComponentModel;
using System.Data;
using System.IO;

using Microsoft.Practices.EnterpriseLibrary.ExceptionHandling;
using Microsoft.Practices.EnterpriseLibrary.Logging;
using System.Runtime.Remoting.Contexts;

[XmlRoot("PageLayoutControl")]
public class PageLayoutControl : WebControl
{
//constants for property simple property setter value tag replacements
public const string PSV_DOMAIN = "[DOMAIN]";
public const string PSV_ACCOUNTNAME = "[ACCOUNTNAME]";
public const string PSV_MACHINE = "[MACHINE]";
public const string PSV_LOGIN = "[LOGIN]";

#region Properties
private String _fileLocation;
public String FileLocation
{
get
{
return _fileLocation;
}
set
{
_fileLocation = value;
}
}
#endregion

#region Constructor
public PageLayoutControl(String fileLocation)
{
this.FileLocation = fileLocation;
}
#endregion

#region Overriding Events

/// <summary>
/// Overriding the onLoad event of Custom Control.
/// This control is executed with Header place holder is executed in the Page Layout.
/// This code executes once on the page, It checks whether the code is executed
/// on the page, and if not it executes and adds the key to page for this code execution.
/// <param name="e" type="EventArgs">e</param>
/// <returns></returns>
/// </summary>

protected override void OnLoad(EventArgs e)
{
//do the base load functions
base.OnLoad(e);

//look to see if our web has had this stuff run yet
const string KEY_CHK = "PageLayoutControl";

//generic dictionary to store the list of webparts we're going to work 
//with and what we'll do with each; Steve likes generics!  :-)
Dictionary<string, WebPartAction> wpList = null;

//web part action class to store info about web parts that we're changing
WebPartAction wpa = null;

//webpart class that will be used in the action class
System.Web.UI.WebControls.WebParts.WebPart xWp = null;

//assembly we'll use to load web parts we are adding
Assembly wpAsm = null;

//serializer to convert the xml file into objects
XmlSerializer slz = null;

try
{
//get the current web; not using "using" because we don't want to kill
//the web context for other controls that need it

SPWeb curWeb = SPContext.Current.Web;

//turn on unsafe updates so we can make changes on a GET
curWeb.AllowUnsafeUpdates = true;


SPFile oPageLayout = curWeb.GetFile(SPContext.Current.File.Url);


//now that we have the file, read it into an xml document
XmlDocument xDoc = new XmlDocument();
string path = Context.Server.MapPath(_fileLocation);
xDoc.Load(path);

//compare the web part modified dates with the page
string pageWebPartActionsLastMod = string.Empty;
bool processWebPartActionsXml = true;
if (oPageLayout.Properties.ContainsKey(KEY_CHK))
if (xDoc.SelectSingleNode("WebParts") != null)
if (xDoc.SelectSingleNode("WebParts").Attributes["LastModified"] != null)
{
pageWebPartActionsLastMod = xDoc.SelectSingleNode("WebParts").Attributes["LastModified"].InnerText;

if (oPageLayout.Properties[KEY_CHK].ToString() == pageWebPartActionsLastMod)
processWebPartActionsXml = false;
}

//conditional block for processing webpart XML actions file
if (processWebPartActionsXml)
{
//check the page out
if (oPageLayout.CheckOutStatus == SPFile.SPCheckOutStatus.None)
SPSecurity.RunWithElevatedPrivileges(delegate { oPageLayout.CheckOut(); });

try
{

//create a hashtable to store our web parts
wpList = new Dictionary<string, WebPartAction>();

//create a new serializer
slz = new XmlSerializer(typeof(WebPartAction));

int webpartCount = 0; 
//enumerate through the child nodes
foreach (XmlNode xNode in xDoc.FirstChild.ChildNodes)
{
try
{
//try serializing each one
wpa = slz.Deserialize(new System.IO.StringReader(xNode.OuterXml)) as WebPartAction;
}
catch (Exception exception)
{
//set our reference to null so we don't try and do something with
//a version that was successfully serialized previously
wpa = null;
}


//make sure we serialized, and also make sure this is an Add
if (wpa != null)
{
switch (wpa.action)
{
case WebPartAction.ActionType.Add:

//now try loading the assembly
try
{
wpAsm = Assembly.Load(wpa.assemblyName);
}
catch (Exception exception)
{
//set our reference to null so we don't try and do something with
//a version that was successfully loaded previously
wpAsm = null;
}

if (wpAsm != null)
{
//try creating an instance of the class
try
{
xWp = (System.Web.UI.WebControls.WebParts.WebPart)wpAsm.CreateInstance(wpa.className);
}
catch (Exception exception)
{
//set our reference to null so we don't try and do something with
//a version that was successfully loaded previously
xWp = null;
}

//plug it into our class
if (xWp != null)
{
//enumerate and add properties to part
SetWebPartProperties(wpa, xWp);

//add part to class
wpa.wp = xWp;
}
}

//add it to the hashtable
wpList.Add(Guid.NewGuid().ToString(), wpa);
break;
default:
//for delete, move or SetProperties we want to capture 
//the type name and plug it into the hash array
webpartCount++;
if ( !wpList.ContainsKey(wpa.typeName.ToString() + webpartCount.ToString()))
wpList.Add(wpa.typeName.ToString() + webpartCount.ToString(), wpa);
break;
}
}
}

//get the web part manager
SPLimitedWebPartManager theMan = oPageLayout.GetLimitedWebPartManager(System.Web.UI.WebControls.WebParts.PersonalizationScope.Shared);
webpartCount = 0;
foreach (System.Web.UI.WebControls.WebParts.WebPart wp in theMan.WebParts)
{
//Increments webpart counter........
webpartCount++;
//check each web part to see if matches our typeName
if (wpList.ContainsKey(wp.GetType().ToString() + webpartCount.ToString()))
wpList[wp.GetType().ToString() + webpartCount.ToString()].wp = wp;
}

//now enumerate items in hash; can't do it in WebPart collection 
//on SPLimitedWebPartManager or it fails
foreach (string key in wpList.Keys)
{
wpa = wpList[key];
if (wpa.wp != null)
{
switch (wpa.action)
{
case WebPartAction.ActionType.Delete:
theMan.DeleteWebPart(wpa.wp);
break;
case WebPartAction.ActionType.Move:
theMan.MoveWebPart(wpa.wp, wpa.zoneID, int.Parse(wpa.zoneIndex));
theMan.SaveChanges(wpa.wp);
break;
case WebPartAction.ActionType.Add:
theMan.AddWebPart(wpa.wp, wpa.zoneID, int.Parse(wpa.zoneIndex));
break;
case WebPartAction.ActionType.SetProperties:
SetWebPartProperties(wpa, wpa.wp);
theMan.SaveChanges(wpa.wp);
break;
}
}

}

//add our key to the property bag so we don't run our provisioning code again
if (oPageLayout.Properties.Contains(KEY_CHK))
{
oPageLayout.Properties[KEY_CHK] = pageWebPartActionsLastMod;
}
else
{
oPageLayout.Properties.Add(KEY_CHK, pageWebPartActionsLastMod);
}


oPageLayout.Update();

// for making the page appear in edit mode when first provisioned.

////check the page in and publish
// to be executed when migrated pages which should have been published before.
if (oPageLayout.MajorVersion >= 1 )
{
SPSecurity.RunWithElevatedPrivileges(delegate
{
try
{
oPageLayout.CheckIn(string.Format(" -- checked in on {0}", DateTime.Now));
oPageLayout.Publish(string.Format(" -- published on {0}", DateTime.Now));
}
catch (Exception ex)
{ }
});
}
// To be executed when new site is create with a layout as default page.
if (oPageLayout.Versions.Count == 1 && oPageLayout.MinorVersion == 1 && oPageLayout.CheckOutStatus == SPFile.SPCheckOutStatus.None )
{
SPSecurity.RunWithElevatedPrivileges(delegate
{
try
{
oPageLayout.CheckOut(); 
}
catch (Exception ex)
{ }
});
}
curWeb.AllowUnsafeUpdates = false;


Context.Response.Clear();
Context.Response.Redirect(oPageLayout.Name + "?ControlMode=Edit&DisplayMode=Design", false);

//potentially delete our xml manifest file that tells us what to do
//would be cool if we could just remove ourselves from the page
//or maybe we stay there so we could be activated again in the future?? That
//would be an interesting idea...
}

catch (Exception exception)
{
if (ExceptionPolicy.HandleException(exception, "Iti Exception"))
{

}
}
}

}
catch (Exception exception)
{
}
}
#endregion

#region Custom Methods

/// <summary>
/// This method sets the WebPart Properties before placing them on the page.
/// It checks if the Web Part Properties are specified in the Xml file.
/// Property Name "Title" and "Associated List Name".
/// <param name="wpa" type="WebPartAction">wpa</param>
/// <param name="xWp" type="System.Web.UI.WebControls.WebParts.WebPart">xWp</param>
/// <returns></returns>
/// </summary>

private void SetWebPartProperties(WebPartAction wpa, System.Web.UI.WebControls.WebParts.WebPart xWp)
{
//check to see if there are any properties; if there are zero it won't say
//zero, it will say null (unlike vb.net)
if (wpa.Properties == null)
return;

//enumerate and add properties to part
for (int p = 0; p < wpa.Properties.Property.Length; p++)
{
try
{
// checks the "Type" attribute of property and calls the appropriate method to get property value.
switch (wpa.Properties.Property[p].Type.ToString().ToLower())
{
case "string":
xWp.GetType().GetProperty(wpa.Properties.Property[p].Key).SetValue(xWp,
GetPropertySetterValue(wpa.Properties.Property[p].Value), null);
break;
case "partchromestate":
xWp.GetType().GetProperty(wpa.Properties.Property[p].Key).SetValue(xWp,
GetPropertySetterPartChrome(wpa.Properties.Property[p].Value), null);
break;
}

}

catch (Exception exception)
{
if (ExceptionPolicy.HandleException(exception, "Iti Exception"))
{
//  throw;
}
}

}
}

/// <summary>
/// This is a property getter method which gets the WebPart Property
/// of Type string. This methods set the property for all string type properties.
/// Property Name "Title" and "Associated List Name".
/// <param name="Value" type="string">Value</param>
/// <returns name="ret" type="string">ret</returns>
/// </summary>

private string GetPropertySetterValue(string Value)
{
try
{
string ret = Value;

switch (Value)
{
case PSV_ACCOUNTNAME:
ret = Environment.UserName;
break;
case PSV_DOMAIN:
ret = Environment.UserDomainName;
break;
case PSV_MACHINE:
ret = Environment.MachineName;
break;
case PSV_LOGIN:
ret = Environment.UserDomainName + "\\" + Environment.UserName;
break;
default:
break;
}

return ret;
}
catch (Exception exception)
{
if (ExceptionPolicy.HandleException(exception, "Iti Exception"))
{
//  throw;
}
return null;
}

}

/// <summary>
/// This is a property getter method which gets the WebPart Property
/// of Type PartChromeState. Its has two states Normal / Minimized
/// <param name="Value" type="string">Value</param>
/// <returns name="chState" type="PartChromeState">chState</returns>
/// </summary>

private PartChromeState GetPropertySetterPartChrome(string Value)
{
try
{
PartChromeState chState = PartChromeState.Normal;

// checks if its find the xml attribute "Minimized"
// Sets the WebPart State to Minimized.
if (Value == "Minimized")
{
chState = PartChromeState.Minimized;
}
return chState;
}
catch (Exception exception)
{
return PartChromeState.Normal;
}
}

#endregion
}

#region WebPart Property Class

/// <summary>
/// Class defines the WebPart Actions the are required to place 
/// the WebParts by default when the instance of Page Layout is created.
/// These actions corresponds to xml elements that are nested under <PageLayout> </PageLayout> element.
/// </summary>

public class WebPartAction
{
/// <summary>
/// Enumerating the Actions that can be applied to WebParts.
/// </summary>
public enum ActionType
{
Delete,
Add,
Move,
SetProperties
}

#region WebPartAction Properties

[XmlIgnore()]
public System.Web.UI.WebControls.WebParts.WebPart wp = null;

/// <summary>
/// Specify Assembly Name.
/// </summary>
[XmlElement(Form = XmlSchemaForm.Unqualified)]
public string assemblyName = string.Empty;

/// <summary>
/// Specify Class Name.
/// </summary>
[XmlElement(Form = XmlSchemaForm.Unqualified)]
public string className = string.Empty;

/// <summary>
/// Specify Web Part Zone ID.
/// </summary>
[XmlElement(Form = XmlSchemaForm.Unqualified)]
public string zoneID = string.Empty;

/// <summary>
/// Specify Web Part Zone Index.
/// using a string to greatly simplify potential errors during deserialization.
/// </summary>
[XmlElement(Form = XmlSchemaForm.Unqualified)]
public string zoneIndex = "0";

/// <summary>
/// Specify Type Name.
/// </summary>
[XmlElement(Form = XmlSchemaForm.Unqualified)]
public string typeName = string.Empty;

/// <summary>
/// Specify Web Part Action (Add, Delete, Move or Set Properties).
/// </summary>
[XmlElement(Form = XmlSchemaForm.Unqualified)]
public ActionType action;

/// <summary>
/// Specify Web Part Properties.
/// </summary>
[XmlElement(Form = XmlSchemaForm.Unqualified)]
public PropertyRoot Properties;

#endregion

#region Constructors

/// <summary>
/// Parameterless constructor for WebPart Action Class. 
/// <param></param>
/// <returns></returns>
/// </summary>
public WebPartAction()
{
//parameter-less constructor needed for serialization
}

/// <summary>
/// Parameterized constructor for WebPart Action Class. 
/// Used to deserilaize the xml with WebPart Actions defined. 
/// <param name="wp" type="System.Web.UI.WebControls.WebParts.WebPart">wp</param>
/// <param name="action" type="ActionType">action</param>
/// <returns></returns>
/// </summary>
public WebPartAction(System.Web.UI.WebControls.WebParts.WebPart wp, ActionType action)
{
this.wp = wp;
this.action = action;
}

/// <summary>
/// Parameterized constructor for WebPart Action Class. 
/// Used to deserilaize the xml with WebPart Actions, Zone ID and Zone Index defined. 
/// <param name="wp" type="System.Web.UI.WebControls.WebParts.WebPart">wp</param>
/// <param name="action" type="ActionType">action</param>
/// <param name="zoneID" type="string">zoneID</param>
/// <param name="zoneIndex" type="string">zoneIndex</param>
/// <returns></returns>
/// </summary>
public WebPartAction(System.Web.UI.WebControls.WebParts.WebPart wp, ActionType action, string zoneID, string zoneIndex)
{
this.wp = wp;
this.action = action;
this.zoneID = zoneID;
this.zoneIndex = zoneIndex;
}

#endregion


#region WebPart Property Class

/// <summary>
/// Class specify the webpart properties.
/// Get the array of properties in the form of xml elements,
/// with its attributes as property values.
/// </summary>

public class PropertyRoot
{
[XmlElement(Form = XmlSchemaForm.Unqualified)]
public OneProperty[] Property;
}

#endregion

#region Property Attributes Class

/// <summary>
/// Class defines the webpart property attributes.
/// Three attributes of property can be defined,
/// <Key> <Type> <Value>
/// </summary>
public class OneProperty
{
[XmlAttribute(Form = XmlSchemaForm.Unqualified)]
public string Key = string.Empty;

[XmlAttribute(Form = XmlSchemaForm.Unqualified)]
public string Type = string.Empty;

[XmlAttribute(Form = XmlSchemaForm.Unqualified)]
public string Value = string.Empty;
}
#endregion
}
#endregion