Friday, January 21, 2011

SharePoint 2010 Tips and Tricks

1. Change Site Icon/Logo of all pages in SharePoint 2010 (Wiki pages and Web part pages)

a. Wiki Pages:

Navigate to following path-
Site > Site Actions > Site Settings > Look and Feel > Title, description, and icon > URL

In URL textbox we can specify either Site Asset’s Image or 14 hive image.
Reference:
Change Wiki Page Site Logo

b. Web Part Pages:

  • Open Web Part page
  • Select Page ribbon Tab on top
  • Select Title Bar Properties
  • Scroll to the right and on the Web Part Page Title Bar properties
  • Specify either Site Asset’s Image or 14 hive image

Reference:
Change Web Part Page Site Logo



2. Enable Anonymous in SharePoint 2010


  1. Open SharePoint 2010 Central Administration
  2. Navigate to following path:
    Central Administration > Application Management > Manage web applications
  3. Select desired Web Application
  4. Click Authentication Providers icon in ribbon tab
  5. On the Authentication Providers pop-up window click on the Default zone.
  6. Under Edit Authentication, check Enable anonymous access and click Save.
  7. Go back to Web Application Management click on the Anonymous Policy icon in ribbon tab.
  8. Under Anonymous Access Restrictions select your Zone and set the Permissions to None – No policy and click Save.
  9. Now, open the desired web application in which we want to set anonymous access.
  10. Navigate to your top level site collection for the web application.
  11. Click the Site Actions > Site Settings > Users and Permissions > Site permissions.
  12. Under Permission Tools ribbon, click Anonymous Access icon
  13. Set the permissions to Entire Web site, or List and Libraries, or Nothing as per requirement
  14. Click OK.
  15. In case of Anonymous access at Web site level:
  • Navigate to Web Site > Site Actions > Site Permissions
  • Click Stop Inheriting Permissions icon in Permission Tools ribbon tab
  • After that we can see Anonymous Access icon in ribbon, click it
  • In Anonymous Access pop-up select desired check box as per requirement
  • Click Ok
        In case of Anonymous access at List and Library level:
  • Navigate to List or Library > List Tool tab > List tab > List Settings icon in ribbon > Permissions and Management > Permissions for this list
  • Click Stop Inheriting Permissions icon in Permission Tools ribbon tab
  • After that we can see Anonymous Access icon in ribbon, click it
  • In Anonymous Access pop-up select desired check box as per requirement
  • Click Ok

Reference:
Enable Anonymous Access 1
Enable Anonymous Access 1


3. Steps to use or consume SharePoint List or Libraries RSS functionality

  • If we are planning to use out-of-box RSS functionality of SharePoint’s List or Libraries using out-of-box RSS Viewer web part of SharePoint, then we have to enable Anonymous access at List or Library level.
  • If anonymous access is disabled at List or Library level then we will get following error:
    “The RSS webpart does not support authenticated feeds”

To solve the above error there are following options:

  • Set anonymous access at List or Library level
  • Use 3rd party RSS Feed Reader [available in Codeplex site]
  • Set IIS Authentication from NTLM to Kerberos
    [Central Administration > Application Management > Manage web applications > Select desired Web application > Select Authentication Providers icon in ribbon tab > Click Default link in Authentication Providers pop-up > Edit Authentication pop-up > IIS Authentication Settings > Integrated Windows Authentication > Select Negotiate (Kerberos)]


Note: As per me first option i.e. set anonymous access is best one.


4. Master page branding or UI change in SharePoint 2010

[Note: It’s was my personal experience]
I tried to change the HTML code of default.master or V4.master page/file using SharePoint 2010 Designer (SPD).
SPD reflected all changes, but when I browsed any content page, it didn’t displayed the desired changes.

Solution [as per me]:
I created a copy of default.master or V4.master and renamed it as per requirement. Made all the required HTML changes in it and saved it. Right clicked on the new custom master page and selected the Set as Default Master Page option. Changes get reflected in both SPD and all the browsed content pages.


5. How to hide first tab of SharePoint 2010 site

We need to add following CSS class to hide first tab of SharePoint 2010 site:

.s4-tn li.static:first-child{ 
display: none; 
}


Why we need to hide the first tab???
Ans: There is well known tab selection issue in SharePoint 2010. When we select first tab, second tab always remain selected (wrong tab selection as per UI). To solve this issue, I made the first tab invisible and made the second tab as home page tab. So by this when user clicks the first visible tab, he actually clicks the second tab and hence there is no UI confusion regarding tab selection.



6. Error :
Error occurred in deployment step 'Retract Solution': A deployment or retraction is already under way for the solution "MySolution.wsp", and only one deployment or retraction at a time is supported.

Solution:
a. Enumerates all pending and active deployments in the farm using following command:
stsadm -o enumdeployments

b. Cancel the troublesome Solution that was causing problem [specify the Solution GUID using above command]:
stsadm -o canceldeployment -id <solution GUID>


Reference:
SharePoint deployment or retraction issue



Friday, October 22, 2010

Display SharePoint ListItem's Attachments

Steps to create a separate page to display all the attachments of a particular SPListItem using SharePoint Designer:

1. Create an ASPX page using SharePoint Designer (SPD).



2. Add a DataView control in page in-between HTML form tag.
Note: First save the page then add control.



3. Select the Data Source Library.
Select your SharePoint List (in my case it is MyTest SPList). Open its context menu and select Show Data


4. Select columns you want to keep in Data Source Details.



5. Insert Selected Fields as Single Item View



6. Now some code changes:
a. Add some CSS style above closing head tag [optional]
<style type="text/css">
.ms-vb a
{
    font-family:Verdana;
    font-size:x-small;
}
</style>
</head>

b. Place your selected columns/fields
Location followig code snippet:
<xsl:template name="dvt_1.rowview">
<tr>

and insert following code in-between them:

<xsl:template name="dvt_1.rowview">[Original code - 1]
<tr style="color:maroon;font-weight:bold; font-family:Tahoma; font-size:small;">
    <td>
        Attachments                       
    </td>
</tr>
<tr class="ms-alternating" style="font-family:Tahoma; font-size:x-small;">
    <td>
        SharePoint ListItem ID - <b><SharePoint:FieldValue FieldName="ID" ControlMode="Display" runat="server" Visible="true" /></b>
    </td>
</tr>             
<tr class="ms-formbody" style="font-family:Tahoma; font-size:xx-small;">
    <td>
        <SharePoint:AttachmentsField ControlMode="Display" FieldName="Attachments" runat="server" Visible="true"/>
    </td>
</tr>
<tr style="display:none;">[Original code - 2]

Note-Here we are hiding the existing TR row


c. Hide paging control
Locate following code snippet:

<td nowrap="" class="ms-paging" align="right">

and hide that TD.
changed snippet:

<td style="display:none;" nowrap="" class="ms-paging" align="right"> 


7. Now open the page in browser and passed SPListItem as query string.
example: http://[server-name]:[port-number]/[page-name].aspx?ID=1


Tuesday, September 14, 2010

Code to search files with particular extension in SharePoint's Web Application

Requirement:
To search files with particular extension [here *.doc as example].

Here to achieve the above requirement I used SharePoint's Object Model.

I downloaded those searched files to a particular folder.
Beside printing the searched files result in console and I am also logging it in a Log file.


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint;
using System.IO;
using System.Collections;

namespace SearchFile
{
    class Program
    {
        static void Main(string[] args)
        {
            //Get folder path
            string directoryPath
                = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)
                , "MyFolder");

            //Create directory if it not exist
            if (!(Directory.Exists(directoryPath)))
                Directory.CreateDirectory(directoryPath);

            //SPFile myFile = null;
            byte[] binFile;
            string filename = string.Empty;
            FileStream fs = null;
            BinaryWriter bw = null;
            SPDocumentLibrary library = null;
            string fileExtension = ".doc";
            string siteURL = "http://[server-name]:[port-number]";
            StringBuilder filesLog = new StringBuilder();

            using (SPSite site = new SPSite(siteURL))
            {
                foreach (SPWeb web in site.AllWebs)
                {
                    foreach (SPList list in web.Lists)
                    {
                        if (list.BaseType == SPBaseType.DocumentLibrary)
                        {
                            library = (SPDocumentLibrary)list;
                            SPFolder folder = library.RootFolder;
                            ArrayList foldersList = new ArrayList();
                            foldersList.Add(folder);

                            foldersList = getFolders(folder, foldersList);

                            //foreach (SPListItem oListItem in library.Items)
                            foreach (SPFolder fold in foldersList)
                            {
                                foreach (SPFile myFile in fold.Files)
                                {
                                    //Download file in file system
                                    //myFile = oListItem.File;
                                    if (myFile.Name.EndsWith(fileExtension,
                                        StringComparison.InvariantCultureIgnoreCase))
                                    {
                                        binFile = myFile.OpenBinary();

                                        //Generate file name
                                        //filename = Path.Combine(directoryPath, myFile.Name);
                                        filename 
                                           = Path.Combine(directoryPath, 
                                                          myFile.Url.Replace("/", "_"));

                                        //Do file write operation
                                        fs 
                                          = new FileStream(filename, 
                                                FileMode.Create, FileAccess.ReadWrite);
                                        bw = new BinaryWriter(fs);
                                        bw.Write(binFile);
                                        bw.Close();

                                        filesLog.Append(string.Concat(web.Url, "/", 
                                                        myFile.Url, ","));
                                        Console.WriteLine(string.Concat(web.Url, "/",
                                                        myFile.Url));

                                    }//End file extension check 
                                }//End All SPFiles
                            }//End All SPFolders
                        }//End check DocumentLibrary
                    }//End All Lists
                }//End AllWebs
            }//End SPSite

            string[] lines = filesLog.ToString().Split(new char[] { ',' });
            System.IO.File.WriteAllLines(directoryPath + "/LOG_List.txt", lines);

            Console.WriteLine("Press any key to Exit...");
            Console.ReadLine();
        }

        //Recursive function to get all nested SPFolders
        static ArrayList getFolders(SPFolder folder, ArrayList foldersList)
        {
            foreach (SPFolder subfolder in folder.SubFolders)
            {
                foldersList.Add(subfolder);
                foldersList = getFolders(subfolder, foldersList);
            }
            return foldersList;
        }
    }
}


Thursday, August 19, 2010

Impersonation in Console/Windows Application

In this post I tried to cover the way to implement Impersonation in Console or Windows application. In Web application by setting Impersonation="True" in web.config we can do Impersonation but in Windows/Console it is not that straight-forward.

Here in Windows/Console we have to perform following steps [as per me]:
1. Write un-managed LogonUser function that will return UserToken based on passed input parameters
2. Get UserToken using LogonUser function
3. Pass UserToken to WindowsIdentity's constructor
4. Do the Impersonation
5. Do the required stuff using Impersonated Identity
6. Undo the Impersonation [Important]


Code Snippet:


using System;
using System.Data;
using System.Data.SqlClient;
using System.Runtime.InteropServices;
using System.Security.Principal;

namespace ImpersonationSample
{
class Program
{
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern bool LogonUser(String lpszUsername,
String lpszDomain, String lpszPassword,
int dwLogonType, int dwLogonProvider, ref IntPtr phToken);


static void Main(string[] args)
{
IntPtr tokenHandle = new IntPtr(0);

const int LOGON32_PROVIDER_DEFAULT = 0;
//This parameter causes LogonUser to create a primary token.
const int LOGON32_LOGON_INTERACTIVE = 2;

tokenHandle = IntPtr.Zero;

string userName = "UserName";
string domainName = "DomainName";
string password = "UserPassword";

// Call LogonUser to obtain a handle to an access token.
bool returnValue = LogonUser(userName, domainName, password,
LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT,
ref tokenHandle);

// Retrieve the Windows identity using the specified token.
WindowsIdentity windowsIdentity = new WindowsIdentity(tokenHandle);

// Create a WindowsImpersonationContext object
// by impersonating the Windows identity.
WindowsImpersonationContext impersonationContext =
windowsIdentity.Impersonate();


string connectionString =
"Data Source=[Server-Name];" +
"Initial Catalog=[Database-Name];" +
"Trusted_Connection=True;" +
"Integrated Security=SSPI;" +
"User Id=[DomainName\\UserName];" +
"password= [UserPassword]";

using (SqlConnection cn = new SqlConnection(connectionString))
{
SqlCommand cmd = new SqlCommand("SELECT COUNT(*) FROM MyTable", cn);
cn.Open();
SqlDataReader rdr
= cmd.ExecuteReader(CommandBehavior.CloseConnection);
rdr.Read();
Console.WriteLine(rdr[0].ToString()); //read a value
}

Console.WriteLine("Name of the identity after impersonation: "
+ WindowsIdentity.GetCurrent().Name + ".");
Console.WriteLine(windowsIdentity.ImpersonationLevel);


// Stop impersonating the user.
impersonationContext.Undo();

// Check the identity name.
Console.Write("Name of the identity after performing an Undo on the");
Console.WriteLine(" impersonation: " +
WindowsIdentity.GetCurrent().Name);

Console.ReadLine();
}
}
}





References:
MSDN Impersonation 1
MSDN Impersonation 1
MSDN Impersonation 1
SQL Connection String Types

Thursday, March 18, 2010

SPFolder related operations in SharePoint

1) Get SPListItem(s) of a particular SPFolder


SPList splist;
SPFolder spfolder; //Get the required folder instance
SPQuery spquery = new SPQuery();
spquery.Query = string.Empty;
spquery.Folder = spfolder;
spquery.ViewAttributes = "Scope=\"Recursive\""; //For nested folder structure

SPListItemCollection itemCol = splist.GetItems(spquery)


2) Create a SPListItem based on a custom ContentType or SPFolder ContentType

SPWeb spweb; //get the SPWeb instance
SPContentType myCType = splist.ContentTypes["Custom content type"];
SPList splist = spweb.Lists["My SPList"];
SPListItem splistitem = splist.Items.Add();
splistitem["ContentTypeId"] = myCType.Id;
splistitem.Update();

splistitem["Title"] = "New Item";
splistitem.Update();


3) Add a SPListItem in a particular SPFolder

SPWeb spweb; //get the SPWeb instance
SPContentType myCType = splist.ContentTypes["Custom content type"];
SPList splist = spweb.Lists["My SPList"];
//get folder instance
SPFolder spfolder = splist.Folders[1];
SPListItem splistitem
= splist.Items.Add(spfolder.ServerRelativeUrl
, SPFileSystemObjectType.File, null);

splistitem["ContentTypeId"] = myCType.Id;
splistitem.Update();

splistitem["Title"] = "New Item";
splistitem.Update();

Image Preview functionality in SharePoint

Question:
How to display the Image preview without actually uploading the file in SharePoint?

Solution:
To check the image preview we can temporary move/place the file in Layout folder. Then pass URL in following format to Image control:
"/_layouts/images/MYFOLDER/MyImageName.jpg

After checking the Image preview and final upload of image file, we can delete the temporary image file from 12 hive.

Code snippet (comments are self-explanatory):


FileUpload FileUploadImage; //FileUpload control to select image file
Image myImage; //Image control to be used for preview functionality

//Getting 12 hive path through SPUtility.GetGenericSetupPath() function
string folderPath =
Microsoft.SharePoint.Utilities.SPUtility.GetGenericSetupPath("TEMPLATE")
+ "\\IMAGES\\MYFOLDER\\";

//Check folder path
if (!Directory.Exists(folderPath))
Directory.CreateDirectory(folderPath);

//Copy the image file to a temporary folder in 12 hive
File.WriteAllBytes(folderPath + FileUploadImage.FileName,
FileUploadImage.FileBytes);

/* //File.Copy() will not work in case of remote image upload
File.Copy(FileUploadImage.PostedFile.FileName,
folderPath + FileUploadImage.FileName, true);
*/

//Set the URL of image control
myImage.ImageUrl =
"/_layouts/images/MYFOLDER/" + FileUploadImage.FileName;


Note: In a similar manner we can preview media file (like *.wmv) before actual upload in SharePoint.

Custom RSS Feed in SharePoint

SharePoint provides SPList’s level RSS Feed url [SPList Toolbar > Actions > View RSS Feed].
http://<server-name:port>/_layouts/listfeed.aspx?List=List_GUID

In above URL by specifying List’s GUID we can get feeds for all records (irrespective of any SPView or of Default View).

Now consider a scenario where we want SPView specific feeds.

In File System, ListFeed.aspx file is placed at following:
C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\LAYOUTS\ListFeed.aspx

ListFeed.aspx refers Microsoft.SharePoint.ApplicationPages.ListFeed.cs class file. Using Reflector we can get the idea that ListFeed.aspx can accept 3 query strings as parameters: List GUID, Meeting Instance ID and View GUID.


Guid guid = new Guid(base.Request.QueryString.GetValues("List")[0]);
string[] values = base.Request.QueryString.GetValues("InstanceID");
string g = base.Request.QueryString["View"];


ListFeed.cs is using following function to get the feeds:

base.spList.WriteRssFeed(base.Response.OutputStream,
base.meetingInstanceId, this.spView);


MSDN Description of WriteRssFeed function:

public void WriteRssFeed (
Stream outputStream,
int meetingInstanceId,
SPView spView
)

Parameters
outputStream : A Stream object that represents the document stream.
meetingInstanceId : An integer value that represents the meeting instance.
spView :An SPView object that represents the view.


WriteRssFeed supports 3 overload methods:
SPList.WriteRssFeed(Stream) :
Writes the RSS feeds from the list to the specified document stream.

SPList.WriteRssFeed (Stream, Int32) :
Writes the RSS feeds from the list that are associated with the specified meeting to the specified document stream.

SPList.WriteRssFeed (Stream, Int32, SPView) :
Writes the RSS feeds from the list that are associated with the specified meeting and view to the specified document stream.

So if we want View specific feed then we have to specify all 3 parameters, but here comes the issue: what does Meeting Instance ID mean and from where we get this value?



Now to get the SPView specific feed, we can write custom RSS Feed. I referred this post- blah.winsmarts.com. I modified the original code little bit. I created a application page and instead of writing inline server code I created a class library so that I can debug the page.

HTML Code:

<%@ Page Language="C#"
Inherits="MyNameSpace.MyFeed,MyNameSpace,
Version=1.0.0.0,Culture=neutral,PublicKeyToken=1d5ac09ccd41620f" %>


C# Code:

using System;
using System.Web;
using System.Text;
using Microsoft.SharePoint;
namespace MyNameSpace
{
public class MyFeed
: Microsoft.SharePoint.WebControls.UnsecuredLayoutsPageBase
{
public void Page_Load()
{
try
{
Response.Write(GetRSSFromListView(
Request.QueryString["List"],
Request.QueryString["View"]));
}
catch (Exception ex)
{
Response.Write("<pre>");
Response.Write(ex.ToString());
Response.Write("</pre>");
}
}
private static string GetRSSFromListView(string strListGUID,
string strViewGUID)
{
StringBuilder sb = new StringBuilder();
sb.Append("<?xml version=\"1.0\"?>");
sb.Append("<rss version=\"2.0\">");

using (SPSite site = new SPSite(SPContext.Current.Web.Url))
using (SPWeb web = site.OpenWeb())
{
SPList list = web.Lists[new Guid(strListGUID)];
SPView view = null;
if (strViewGUID != null)
view = list.Views[new Guid(strViewGUID)];
else
view = list.DefaultView;

sb.Append("<channel>");
AddTag("title", list.Title, sb);
AddTag("description", list.Description, sb);

SPListItemCollection items = list.GetItems(view);
foreach (SPListItem item in items)
{
sb.Append("<item>");
AddTag("title", item["LinkTitle"].ToString(), sb);
AddTag("link", list.RootFolder.Url
+ "/DispForm.aspx?ID=" + item.ID, sb);
sb.Append("<description>");
foreach (string viewField in view.ViewFields)
{
if (viewField != "LinkTitle")
{
AddTag(
viewField.Replace("_x0020_", " "),
HttpContext.Current.Server.HtmlEncode
(item.GetFormattedValue(viewField)),
sb);
}
}
sb.Append("</description>");
sb.Append("</item>");
}
sb.Append("</channel>");
sb.Append("</rss>");
}
return sb.ToString();
}


private static void AddTag(string tagText,
string tagValue, StringBuilder sb)
{
sb.Append("<");
sb.Append(tagText.Replace(" ", "_"));
sb.Append(">");
sb.Append(HttpContext.Current.Server.HtmlEncode(tagValue));
sb.Append("</");
sb.Append(tagText.Replace(" ", "_"));
sb.Append(">");
}
}
}


Now if we use the above custom RSS Feed page URL and pass it to SharePoint’s out-of-box RSS Viewer Webpart, then we will get following error:

The RSS webpart does not support authenticated feeds.

Solution -
Changing to Kerberos authentication
1. On the Central Administration page, click Application Management.
2. Under the Application Security section, click Authentication Providers.
3. Click the Default provider, and change Integrated Widows authentication from NTLM to Negotiate (Kerberos).

OR
We can use custom RSS Viewer WebPart, which is already developed and uploaded at : philwicklund.com


References:
RSS Feed
how-to-get-moss-2007-rss
RSS Reader
Technet
MSDN

Google