Sunday, March 27, 2011

How to fix troubles with internet access in a Windows Server 2008 Std VM that is configured as a domain controller

Scenario:
No internet in domain controller Windows Server 2008 VM? How to fix troubles with internet access in a VM that is configured as a domain controller?

Explanation:
Installed SharePoint Foundation in a Windows Server 2008 Std VM.
Before configuring the server as a domain controller, the VM had access to internet.
Soon after configuring the VM as a domain controller, the server could not access internet from the host machine.

Solution:
After hours of troubleshooting, the below worked :

Go to Control Panel\Network and Internet\Network and Sharing Center

Click Local Network Connection:


Click Properties:


Highlight Internet Protocal Version 4 (TCP/IPv4) and click Properties:



Make sure to choose "Obtain IP Address automatically" and "Obtain DNS server address automatically"

Repeat the same step for IPv6 as well..

Disclaimer: I am not a network admin. This just happened to work for me. I am sharing this so that it could just save some time for some one with the same problem.

PowerShell - How to use named optional parameters in PowerShell?

Scenario:
How to use named optional parameters in PowerShell?

Explanation:
I always wondered whether it is possible to use named optional parameters in PowerShell scripts.
The below script explains how to accomplish it.

Solution:
param([string]$SolutionPath = "", [string]$WebApp = "")
The above line tells PowerShell to extract values from parameters "SolutionPath" and "WebApp".
These values will be used in PowerShell with the same names ($SolutionPath and $WebApp)

Lets save the below code into a ps1 file and name it "NamedParameters.ps1"
#IMPORTANT - The below line should be the first line. There should be nothing before the below line.
param([string]$SolutionPath = "", [string]$WebApp = "")

Write-Host "Solution Path: $SolutionPath"
Write-Host "Web App: $WebApp"
Run the script that we just developed:
.\NamedParameters.ps1 -SolutionPath "D:\Ironworks.SharePoint2010.Features.Core.wsp" -WebApp "http://ironworksdev.com" 
Output:
Solution Path: D:\Ironworks.SharePoint2010.Features.Core.wsp
Web App: http://ironworksdev.com
.\NamedParameters.ps1 -SolutionPath "D:\Ironworks.SharePoint2010.Features.Core.wsp" 
Output:
Solution Path: D:\Ironworks.SharePoint2010.Features.Core.wsp
Web App:
.\NamedParameters.ps1 -WebApp "http://ironworksdev.com" 
Output:
Solution Path:
Web App: http://ironworksdev.com

Hope that this helps someone.

How to build a dynamic query for SPQuery with multiple OR conditions programatically?

Scenario:
How to build a dynamic query for SPQuery object with multiple OR conditions programatically?

Explanation:
In this post, I will try to explain how to build a query for SPQuery object with multiple OR conditions dynamically.

For example: If a programmer attempts to get list items from a list with IDs 1,2,5, 9 and 13 dynamically, he would need to build a query for SPQuery with multiple OR conditions.

The below query seems to work at first glance but it does not work:
<Query>
  <Where>
    <Or>
      <Eq>
        <FieldRef Name="ID" />
        <Value Type="Counter">1</Value>
      </Eq>
      <Eq>
        <FieldRef Name="ID" />
        <Value Type="Counter">2</Value>
      </Eq>
      <Eq>
        <FieldRef Name="ID" />
        <Value Type="Counter">5</Value>
      </Eq>
      <Eq>
        <FieldRef Name="ID" />
        <Value Type="Counter">9</Value>
      </Eq>
      <Eq>
        <FieldRef Name="ID" />
        <Value Type="Counter">13</Value>
      </Eq>
    </Or>
  </Where>
</Query>

The reason why the above query does not work is because there is a hard limit set by SharePoint's SPQuery object to 2 items within an OR condition. The above code would only work for maximum of 2 items:
<Query>
  <Where>
    <Or>
      <Eq>
        <FieldRef Name="ID" />
        <Value Type="Counter">1</Value>
      </Eq>
      <Eq>
        <FieldRef Name="ID" />
        <Value Type="Counter">2</Value>
      </Eq>
    </Or>
  </Where>
</Query>

The correct query for SPQuery should look like the below:
<Query>
  <Where>
    <Or>
      <Eq>
        <FieldRef Name="ID" />
        <Value Type="Counter">1</Value>
      </Eq>
      <Or>
        <Eq>
          <FieldRef Name="ID" />
          <Value Type="Counter">2</Value>
        </Eq>
        <Or>
          <Eq>
            <FieldRef Name="ID" />
            <Value Type="Counter">5</Value>
          </Eq>
          <Or>
            <Eq>
              <FieldRef Name="ID" />
              <Value Type="Counter">9</Value>
            </Eq>
            <Eq>
              <FieldRef Name="ID" />
              <Value Type="Counter">13</Value>
            </Eq>
          </Or>
        </Or>
      </Or>
    </Or>
  </Where>
</Query>

Solution:
The below code could be used to build a dynamic query for SPQuery object in SharePoint that works with multiple OR conditions:

First we need a data structure that holds all the list item ids.
For this demo, I will create a custom object called "CustomSPItem" and use a generic list collection of my custom objects as data source.

My custom class:
class CustomSPItem
{
    /// <summary>
    /// ID from the SP List
    /// </summary>
    public int Id
    {
        get;
        set;
    }

    //Other Properties here

    public CustomSPItem()
    {
    }

    public CustomSPItem(int id)
    {
        Id = id;
        //Other properties here..
    }
}

Now create a collection of CustomSPItem objects:
List lstCustomSPItems = new List();
lstCustomSPItem.Add(new CustomSPItem(1));
lstCustomSPItem.Add(new CustomSPItem(2));
lstCustomSPItem.Add(new CustomSPItem(5));
lstCustomSPItem.Add(new CustomSPItem(9));
lstCustomSPItem.Add(new CustomSPItem(13));

Time to build dynamic query for SPQuery.
String query = BuildDynamicSPQueryWithMultipleOrConditions(lstCustomSPItems);

Required methods:
#region Build Dynamic SP Query with Multiple Or Conditions
/// <summary>
/// Builds SPQuery with multiple Or conditions
/// TODO: Describe this in more detail
/// </summary>
/// <param name="lstCustomSPItems"></param>
/// <returns></returns>
public static String BuildDynamicSPQueryWithMultipleOrConditions(List<CustomSPItem> lstCustomSPItems)
{
    String query = String.Empty;

    try
    {
        XmlDocument xmlDoc = new XmlDocument();
        XmlElement nodeWhere;

        //Create root node SPListItems
        nodeWhere = xmlDoc.CreateElement("Where");
        xmlDoc.AppendChild(nodeWhere);

        XmlElement nodeOr = null;
        int locCtr = 0;

        if (lstCustomSPItems.Count == 1)
        {
            var customSPItem = lstCustomSPItems[0];

            XmlElement nodeEq = BuildEqNodeForSPQuery(ref xmlDoc, ref nodeWhere);

            BuildEqNodeInnerXmlForSPQuery(ref xmlDoc, ref nodeEq, customSPItem.Id.ToString());
        }
        else
        {
            foreach (var customSPItem in lstCustomSPItems)
            {
                //Increment counter. We will need it to find the last item
                locCtr++;

                if (locCtr == 1)
                {
                    nodeOr = BuildDynamicOrEqCombination(ref xmlDoc, ref nodeWhere, customSPItem.Id.ToString());
                }
                else if (locCtr == lstCustomSPItems.Count)
                {
                    //We will need to include the last 2 nodes in the Or node. Is this the last record?
                    UpdateOrNode(ref xmlDoc, ref nodeOr, customSPItem.Id.ToString());
                }
                else
                {
                    nodeOr = BuildDynamicOrEqCombination(ref xmlDoc, ref nodeOr, customSPItem.Id.ToString());
                }
            }
        }

        query = xmlDoc.InnerXml;
    }
    catch (Exception ex)
    { }

    return query;
}

/// <summary>
/// Update Or node with a new Eq node
/// </summary>
/// <param name="xmlDoc"></param>
/// <param name="nodeParent"></param>
/// <param name="id"></param>
private static void UpdateOrNode(ref XmlDocument xmlDoc, ref XmlElement nodeParent, String id)
{
    XmlElement nodeEq = BuildEqNodeForSPQuery(ref xmlDoc, ref nodeParent);
    nodeParent.AppendChild(nodeEq);

    BuildEqNodeInnerXmlForSPQuery(ref xmlDoc, ref nodeEq, id.ToString());
}

/// <summary>
/// Build Xml node with a combination of Or and Eq
/// </summary>
/// <param name="xmlDoc"></param>
/// <param name="nodeParent"></param>
/// <param name="id"></param>
/// <returns></returns>
private static XmlElement BuildDynamicOrEqCombination(ref XmlDocument xmlDoc, ref XmlElement nodeParent, String id)
{
    XmlElement nodeOr = BuildOrNodeForSPQuery(ref xmlDoc, ref nodeParent);

    XmlElement nodeEq = BuildEqNodeForSPQuery(ref xmlDoc, ref nodeOr);

    nodeOr.AppendChild(nodeEq);

    BuildEqNodeInnerXmlForSPQuery(ref xmlDoc, ref nodeEq, id.ToString());

    return nodeOr;
}

/// <summary>
/// Build Xml node for "Or"
/// </summary>
/// <param name="xmlDoc"></param>
/// <param name="nodeListItem"></param>
private static XmlElement BuildOrNodeForSPQuery(ref XmlDocument xmlDoc, ref XmlElement nodeParent)
{
    XmlElement nodeOr = null;
    try
    {
        nodeOr = xmlDoc.CreateElement("Or");
        nodeParent.AppendChild(nodeOr);
    }
    catch (Exception ex)
    { }
    return nodeOr;
}

/// <summary>
/// Build Xml node for "Eq"
/// </summary>
/// <param name="xmlDoc"></param>
/// <param name="nodeListItem"></param>
private static XmlElement BuildEqNodeForSPQuery(ref XmlDocument xmlDoc, ref XmlElement nodeParent)
{
    XmlElement nodeEq = null;
    try
    {
        nodeEq = xmlDoc.CreateElement("Eq");
        nodeParent.AppendChild(nodeEq);
    }
    catch (Exception ex)
    { }
    return nodeEq;
}

/// <summary>
/// Build Xml node for "Eq"
/// </summary>
/// <param name="xmlDoc"></param>
/// <param name="nodeParent"></param>
private static void BuildEqNodeInnerXmlForSPQuery(ref XmlDocument xmlDoc, ref XmlElement nodeParent, String id)
{
    try
    {
        XmlElement nodeFieldRef = xmlDoc.CreateElement("FieldRef");
        nodeFieldRef.SetAttribute("Name", "ID");

        XmlElement nodeValue = xmlDoc.CreateElement("Value");
        nodeValue.SetAttribute("Type", "Counter");
        nodeValue.InnerText = id;

        nodeParent.AppendChild(nodeFieldRef);
        nodeParent.AppendChild(nodeValue);
    }
    catch (Exception ex)
    {
    }
}
#endregion

The final query that is generated would look like the below:
<Query>
  <Where>
    <Or>
      <Eq>
        <FieldRef Name="ID" />
        <Value Type="Counter">1</Value>
      </Eq>
      <Or>
        <Eq>
          <FieldRef Name="ID" />
          <Value Type="Counter">2</Value>
        </Eq>
        <Or>
          <Eq>
            <FieldRef Name="ID" />
            <Value Type="Counter">5</Value>
          </Eq>
          <Or>
            <Eq>
              <FieldRef Name="ID" />
              <Value Type="Counter">9</Value>
            </Eq>
            <Eq>
              <FieldRef Name="ID" />
              <Value Type="Counter">13</Value>
            </Eq>
          </Or>
        </Or>
      </Or>
    </Or>
  </Where>
</Query>

Thursday, March 24, 2011

How to build a consumer web part in SharePoint 2010 using IWebPartParameters that works with HTML Form Web Part and Filter Web Parts?

Scenario:
How to build a consumer web part in SharePoint 2010 using IWebPartParameters that works with HTML Form Web Part and Filter Web Parts?

Explanation:
The current SharePoint 2010 documentation still includes reference to an API interface which it says is obsolete.

[ObsoleteAttribute("Use System.Web.UI.WebControls.WebParts.IWebPartParameters instead")]
public interface IFilterConsumer

As we can see, the interface displays a message that says "Use System.Web.UI.WebControls.WebParts.IWebPartParameters instead."
Unfortunately, it's hard to find any good examples out there for writing a Web Part that uses the IWebPartParamters interface for consuming the HTML Form Web Part / Filter Web Parts.

There is one brilliant example here but I had to tweak it slightly to get it working.

Solution:
For the purpose of this demo, I need to capture value for "Zip Code" from the provider web part which is an HTML Form Web Part.

We will need to create a public property in the web part called "ProviderZipCode".

Code:

[ToolboxItemAttribute(false)]
    public class DemoWebPart : System.Web.UI.WebControls.WebParts.WebPart, IWebEditable, IWebPartParameters
    {

        #region Private Members

        private List<IFilterValues> _filterProviders;

        IWebPartParameters _provider = null;
        IDictionary _data = null;
        
        #endregion

        #region Public Properties
        
        /// <summary>
        /// Zip Code from provider web part
        /// </summary>
        public string ProviderZipCode
        {
            get;
            set;
        }
        
        #endregion

        #region Constructor
        
        public DemoWebPart()
        {
            _filterProviders = new List<IFilterValues>();
        }
        
        #endregion

        #region Control Events
        
        protected override void OnPreRender(EventArgs e)
        {
            if (this._provider != null)
            {
                this._provider.GetParametersData(new ParametersCallback(SetProviderData));
            }

            //Get the value (zip code) from the provider web part
            String zipCodeFromProvider = GetFilterValue();

            base.OnPreRender(e);
        }
        
        #endregion

        #region IWebEditable Members
        
        EditorPartCollection IWebEditable.CreateEditorParts()
        {
            //Return the editor part used with this web part.  This builds a
            //custom editor with dropdowns and an asset url selector.

            List<EditorPart> editors = new List<EditorPart>();
            editors.Add(new DemoEditorPart());
            return new EditorPartCollection(editors);
        }
        
        #endregion

        #region Webpart Connections - Consumer

        [ConnectionConsumer("Parameters Data")]
        public void SetProvider(IWebPartParameters provider)
        {
            if (provider != null)
            {
                PropertyDescriptorCollection props = TypeDescriptor.GetProperties(this);
                PropertyDescriptor p1 = props.Find("ProviderZipCode", false);

                PropertyDescriptorCollection schemaProps = new PropertyDescriptorCollection(new PropertyDescriptor[] { p1 });

                provider.SetConsumerSchema(schemaProps);
                this._provider = provider;
            }
        }

        public void SetProviderData(IDictionary dict)
        {
            this._data = dict;
        }

        private string GetFilterValue()
        {
            if (this._provider != null && this._data != null)
            {
                if (_data["ProviderZipCode"] != null)
                {
                    ProviderZipCode = _data["ProviderZipCode"].ToString();
                    return ProviderZipCode;
                }
            }
            return "";
        }

        public void SetConsumerSchema(PropertyDescriptorCollection schema)
        {
            throw new Exception("Not implemented.");
        }

        public void GetParametersData(ParametersCallback callback)
        {
            throw new Exception("Not implemented.");
        }

        public PropertyDescriptorCollection Schema
        {
            get { throw new Exception("Not implemented."); }
        }

        #endregion
    }

After the web part is deployed, I have added an HTML Form Web Part.


When we attempt to connect the HTML Web Part (Provider) to the web part we just deployed (I gave it's title "Find Nearest Locations From A ZipCode" ), we can see our web part in the list of connectible web parts.

In the next screen, we see the provider and consumer field names.
As we can notice in the below picture, our custom property "ProviderZipCode" shows up in the consumer field name and T1, the name of the Text Box in the HTML Form Web Part shows up in the provider field name..



How to call SharePoint Web Services from the context of current logged in user from an asp.net web application?

Scenario:
How to call SharePoint Web Services from the context of current logged-in user from an ASP.NET Web Site/Application that has Windows Authentication enabled?

Explanation:
SharePoint 2010/2007 exposes most of its Object Model through web services.
SharePoint Web Services provide methods that you can use to work remotely with a deployment of SharePoint.

A list of SharePoint 2010 web services can be found here
A list of SharePoint 2007 web services can be found here


Its not always a straight forward process to call SharePoint Web Services from the context of current logged in user from an ASP.NET Web Site/Application that has Windows Authentication enabled.

In this post I will try to explain how to connect to SharePoint Web Services in both WCF and good old web service way.


Solution:


The WCF way:

Add a service reference to the web service (Ex: https://SharePointSite.com/_vti_bin/lists.asmx)
In this example, I have named it "ListsServiceReference"

            ListsServiceReference.ListsSoapClient listsServiceReference = new ListsServiceReference.ListsSoapClient();
            listsServiceReference.ClientCredentials.Windows.ClientCredential = System.Net.CredentialCache.DefaultNetworkCredentials;
       
            listsServiceReference.Endpoint.Address = new System.ServiceModel.EndpointAddress("https://SharePointSite.com/_vti_bin/lists.asmx");

            try
            {
                //Check whether the current user has access to the site.
                //Assuming that all the authorized SharePoint users have access to the list "Form Templates", just check if the current user has access to the list.

                var list = listsServiceReference.GetList("Form Templates");

                _isUserAuthenticated = true;
            }
            catch (Exception ex)
            {
                //User does not seem to have access to the list.
                _isUserAuthenticated = false;
            }

Web.Config Modifications:

<system.serviceModel>
  <bindings>
   <basicHttpBinding>
    <binding name="ListsSoap" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard" maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536" messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered" useDefaultWebProxy="true">
     <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384" />
     <security mode="Transport">
      <transport clientCredentialType="Windows" />
     </security>
    </binding>
   </basicHttpBinding>
  </bindings>
  <client>
   <endpoint address="" binding="basicHttpBinding" bindingConfiguration="ListsSoap" contract="ListsServiceReference.ListsSoap" name="ListsSoap" />
  </client>
 </system.serviceModel>

The Web Service way:


Add a web reference to the SharePoint Web Service.
In this example, I have named it "ListsService"

                try
                {
                    ListsService.Lists listService = new ListsService.Lists();
                    listService.Credentials = System.Net.CredentialCache.DefaultNetworkCredentials;
                    listService.Url = "https://SharePointSite.com/_vti_bin/lists.asmx";

                    //Check whether the current user has access to the site.
                    //Assuming that all the authorized SharePoint users have access to the list "Form Templates", just check if the current user has access to the list.
                    var listNodes = listService.GetList("Form Templates");

                    _isUserAuthenticated = true;
                }
                catch (Exception ex)
                {
                    //User does not seem to have access to the list.
                    _isUserAuthenticated = false;
                }

The important thing to do to make the ASP.NET web service calls work is to make sure that the site needs to have ASP.NET Impersonation and Windows Authentication enabled and that the site  runs in "Classic .NET AppPool" Application Pool.

Sunday, March 13, 2011

How to prevent asp.net UpdatePanel to prevent doing post backs from a custom control

Scenario: 
How to prevent asp.net UpdatePanel to prevent doing post backs from a custom control?

Explanation:
Asp.net UpdatePanel is primarily used for performing asynchronous postbacks with partial page updates. After adding an UpdatePanel control to your page, you can achieve a partial-update of your page on a postback. Only the content in the UpdatePanel is refreshed, the other parts of the page remain unchanged.

You may experience scenarios when controls that are placed inside an UpdatePanel cause the whole page to raise a post back.

Resolution:
Each control inside the update panel need to have an id assigned. After all the controls inside the update panel are assigned ids, the controls inside the UpdatePanel wont cause the page to raise post backs anymore.

How to enable VariationLabelMenu control in SharePoint 2010?

Scenario: 
How to enable VariationLabelMenu control in SharePoint 2010?

Explanation:
SharePoint 2010 (and MOSS 2007) ships with a control called VariationLabelMenu that can be used on sites with site variations enabled. This control enables users to navigate to the related/equivalent pages in other language sites (for which the language packs are installed)

Even though this control is provided OOB in SharePoint 2010, few steps need to be followed to get it to work.

After everything has been configured correctly, you will see a nice little menu that looks like in the below picture. You can place it in the master page or page layout according to your needs.


In my case, I have german language pack installed and therefore the VariationLabelMenu control displays "Deutsch" in the dropdown options.

Solution:

Step-1: 
Go to the location Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\TEMPLATE\CONTROLTEMPLATES, find the file "VariationsLabelMenu.ascx" and edit it.
Add the below line to the contents of the file.

<cms:VariationsLabelEcbMenu id ="varlabelmenu1" DataSourceID="LabelMenuDataSource" DisplayText="Links" IsCallbackMode="true" runat="server" />






After this change, the VariationLabelMenu shows up in the ribbon but it messes up with the existing controls in the ribbon which is not very pleasant.

The side effects due to the above change are as below:


As you can notice in the above picture, the page editing options have been messed up.
Ideally it should look like below:


Also the welcome control that displays the UserContextMenu will be replaced with the VariationLabelMenu control as shown below:



From what I have noticed, the reason for the disappearance of the welcome menu and the improper display of the page editing options in the ribbon are because of the VariationLabelMenu. So if we hide it in the ribbon and show it somewhere else on the page, things will look normal again.

I have searched for the VariationLabelMenu control's markup in the HTML generated by SharePoint. In my case, it is ctl00_ctl34_varlabelmenu1. The control ID may change depending on your master page settings
<style type="text/css">
      #ctl00_ctl34_varlabelmenu1 {display:none;}
</style>  
Include the above code any where in the master page / page layout and it will hide the VariationLabelMenu control in the ribbon.

Now it's time to add the VariationLabelMenu control somewhere else on the page.
Add the below line of code at the top of the master page.
<%@ Register TagPrefix="PublishingVariations" TagName="VariationsLabelMenu" src="~/_controltemplates/VariationsLabelMenu.ascx" %>  

Find an appropriate location in the master page / page layout and add the below line of code which renders the VariationLabelMenu on the page.
<PublishingVariations:VariationsLabelMenu id="labelmenu1" runat="server"/>
Your pages should now display the VariationsLabelMenu properly.

"The remote server returned an error: (401) Unauthorized." exception when you try to access a file in SharePoint Document Library

Scenario:
You receive an exception "The remote server returned an error: (401) Unauthorized." when you try to access a file in SharePoint Document Library.

Explanation:

When you try to access a document in a SharePoint site without anonymous access turned on in the below manner, you would receive a 401 unauthorized error.

XmlDocument xDocument = new XmlDocument();
xDocument.Load(String.Format("{0}{1}", SPContext.Current.Web.Url, XmlFileLocation));

Resolution:

Try to access the file as below:

SPFile configFile = SPContext.Current.Web.GetFile(String.Format("{0}{1}", SPContext.Current.Web.Url, XmlFileLocation));
XmlDocument xdoc = new XmlDocument();
byte[] fileBytes = configFile.OpenBinary();
Stream streamFile = new MemoryStream(fileBytes);
xdoc.Load(streamFile);