Monday, December 28, 2009

STSADM AddSolution failed to extract the cab file in the solution

Title: Error: Stsadm AddSolution failed to extract the cab file in the solution

Details: When tried to addsolution using stsadm command, some times the above error is experienced. Now, what to look for?

Steps:
Step#1: Extract your .wsp file
Step#2: Check the contents and make sure there are no duplicates ( files or resources )
Step#3: See if you have any files with special characters including brackets ' copy (2) filename ' so on and so forth.
Step#4: Clean up unwanted files and rebuild your .wsp.
Step#5: Addsolution this time and verify.

You should be good now.

The query results cannot be enumerated more than once

Title: Error: The query results cannot be enumerated more than once

Details: Ever tried using Linq DataContext model ( using the dbml file ) and try iterating from the return type ISingleResult ? If so, you might have got the error for sure. So, the simple way to do it is to obtain the results to a generic list as shown below.

Code: Consider that GetUserDetails returns a ISingleResult generic list type of GetUserDetailsResult

List<GetUserDetailsResult> results = GetUserDetails().ToList();
foreach (GetUserDetailsResult result in results)
{
// Write your code here...
}

Friday, December 25, 2009

SharePoint 2010 Sandboxed Solutions

Title: SharePoint 2010 Sandboxed Solutions

Introduction: How many times ( as a developer ) have you felt you wanted to have control on testing, staging or productions servers to deploy your solution? and how many times you might have bothered your engineering team for deployment? Similarly, how many times the engineering team might have cursed you for going to them many times to redeploy your solutions? Sounds familiar situation? Well with the introduction of Sandboxed Solutions, its a great relief to both the teams. Lets see in short in the post and I will write separately on each topic in other posts.

Sandboxed Solutions: With elevated previlages ( site collection administrators ), now you can deploy your solutions (.wsp) at the site collection level and fully control them. So, all you need is to request your engineering groups to add you to the Site collection administrators group on the target site collection. With SB Solutions, one can guarentee trust (partial) as well as protection to the farm. Since the SBS's work on a site collection, if any thing goes wrong only that site collection is compromised and would isolate the other Site collections, Web Application as well as Farm. SBS works on a different thread (SPUCWorkerProcess) and doesnt run on the same app pool. This isolation guarentees further more safety.

Build - Deploy: With VS 2010 one can opt for creating a SB Solution Project (default). However when the same solution is deployed at Farm Level, it runs with full trust where as at the site collection level it runs under partial trust. The output of the VS project would be a .wsp which you can upload to the Solutions store under the site collection. You can as well directly use the deploy option of VS however it may not be a suitable for staging and production deployments. You would simple Activate it ( equivalent to deploying the .wsp ) to run your underneath resources. When you donot need it, simply De-Activate the same.

Limitations: You cannot acheive everything using SBS's. As mentioned earlier since its partially trusted donot assume you can attempt to write everything using SBS. Here is list of ( some of ) what you can create

  • Web Parts ( not visual webparts )

  • Site Pages ( not application pages with code behind )

  • List Definitions

  • Event and Feature receivers

  • Infopath form services

  • Custom Actions

  • Content Type and Site Columns

  • JS, AJAX, SilverLight, jQuery ...



Monitoring and Validating: Farm Admins can monitor using the site quota's under CA and specify locks. Alternatively, using SPSolutionValidator Farm admins can monitor and validate the solutions that allow only code signed with a particular certificate to run.

Monday, December 21, 2009

Installing SharePoint 2010 Beta

Title: Installing SharePoint 2010 Beta

Preface: I failed trying to install SharePoint 2010 Beta more than 8 times and finally I was able to do it today. Here is what I did so far and finally what worked out. Installing it on a Windows 7 or Vista OS targetting developer user is no brainer. Simply follow this link and I was able to do it first time. However, my motto is to install it on a Virtual Machine ( VMWare ). So, I started with VMWare 7.0 with 4 core, 4GB RAM, 60GB HDD etc to begin with. I tried to install on both Windows Server 2008 Ent x64 and Windows Server 2008 R2 x64 versions. And when ever I tried to install with pre requisite setup etc, never been successful. Below are few errors I faced ( not all included ).

Errors:
#1 Application Server Role: Web Server (IIS) Role: configuration error
#2 pending restart of the computer.

References: Though I was unsuccesful installing it, these are great resources to follow and give ultimate information.
Sahil Malik's Blog
Jie Li's Blog
Code Project
Patrick's Blog

Finally: I went back to basics... ( my VM settings are same as mentioned above, no changes )
Step #1 Installed Windows 2008 Server 'Standard' Edition and ran the windows updates ( including SP2 ).
Step #2 Installed KB971831
Step #3 Ran the pre-req tool ( ran successful )
Step #4 Installed SPS 2010 > Chose Server Farm and chose StandAlone ( this would install SQL express 2008 )
Step #5 Installed Office Professional 2010
Step #6 Installed SharePoint Designer 2010
Step #7 Installed Visual Studio 2010 Beta
Step #8 Installed SQL Server Management Studio 2008
Step #9 Ran the Windows Update once again
Step #10 Take a snapshot

Voila!!!!

Thursday, December 17, 2009

Reading App.Config Key Values from Feature Folder

Title: Reading App.Config Key Values from Feature Folders
Details: We had a scenario where we need to have App.config under the Feature Folder. Keeping aside the need, the requirement was to read these values from a class thats inheriting SPItemEventReceiver which means I cannot use the Feature.xml properties. One way to accomplish this is as shown below. This is just a raw code, and you can tweak the code for best practices etc.
Code:

private string GetAppSettingValue(string key)
{
string ret = string.Empty;
string appconfigFilePath = Path.Combine(SPUtility.GetGenericSetupPath("TEMPLATE"), @"FEATURES\FEATURENAME\App.config");

ConfigXmlDocument document = new ConfigXmlDocument();
document.Load(appconfigFilePath);
XmlNodeList xmlNodeList = document.GetElementsByTagName("add");

for(int i=0; i < xmlNodeList.Count; i++)
{
if(xmlNodeList[i].Attributes["key"].Value.ToLowerInvariant() == key.ToLowerInvariant())
{
ret = xmlNodeList[i].Attributes["value"].Value;
}
}

return ret;
}

BreakRoleInheritance Method

Title: SPList.BreakRoleInheritance Method
Details: BreakRoleInheritance would break the inheritance ( can be used on a list / document library ) to alter permissions on the parent or itemlevel.
Usage:

public void BreakRoleInheritance (
bool CopyRoleAssignments
)

Accepts either true / false as parameter that would decide whether or not to copy the existing groups / users and permissions.

One interesting concept to note. Instead of using the below code that would remove all the groups and permissions from an item or list level after breaking the inheritance.


listItem.RoleAssignments.RemoveAll();


we can simple use as below


listItem.BreakRoleInheritance(false);

Removing Group / User Permissions on list item

Title: Removing Group / User Permissions on the List Item
Details: Some point of time you will encounter a scenario that you would want to remove permission of a group or user for a specific list item. So, here is what can be done.

Step # 1: Create a Feature and on Activation, Add Event Receivers to the List / Document Library

web.Lists[docLibraryName].EventReceivers.Add(SPEventReceiverType.ItemAdded, AssemblyName, ClassName);


Step # 2: On the Item Event Receiver, you can check for some validations ( or rules )etc and break the inheritance and remove the group.

private static void RemoveGroupPermissionsToTheItem(string groupName, SPWeb web, SPListItem listItem)
{
if (!listItem.HasUniqueRoleAssignments)
{
listItem.BreakRoleInheritance(true);

SPGroup group = web.SiteGroups[groupName];
listItem.RoleAssignments.RemoveById(group.ID);
}
}


Step # 3: On Feature Deactivation, make sure you delete the event handler on the list / documentlibrary


private void DeleteItemAddedEventReceiver(SPDocumentLibrary documentLibrary)
{
SPEventReceiverDefinitionCollection eventReceiverDefinitionCollection = documentLibrary.EventReceivers;

foreach (SPEventReceiverDefinition eventReceiverDefinition in eventReceiverDefinitionCollection)
{
if (eventReceiverDefinition.Assembly == AssemblyName && eventReceiverDefinition.Type == SPEventReceiverType.ItemAdded)
{
eventReceiverDefinition.Delete();
break;
}
}
}

Thursday, November 26, 2009

Installing SharePoint Server 2010 on Windows 7

Title: Installing SharePoint Server 2010 on Windows 7 / Setting Up the Development Environment for SharePoint

Details: Here is a very nice article that would help you set up your development environment on Windows 7.

http://msdn.microsoft.com/en-us/library/ee554869(office.14).aspx

Thursday, November 19, 2009

Speaking at SharePoint Saturday DC

Here is the code and presentation.

Title: Speaking at SharePoint Saturday DC

Date: Dec 5th 2009

Location: Microsoft Technology Center, 12012 Sunset Hills Rd. Reston, VA 20190

Topic: 'Migrating ASP.NET Web Applications to SharePoint Platform' - an ongoing business need

Details: With SharePoint and its advantages - many projects in organizations are ready to migrate from ASP.NET to SharePoint platform. This has become one of the strongest business case and there are instances when developers have questions on ‘How-To’? This session would give an outline of methods, procedures, best practices on real time experience approach.

Speaking at SharePoint Saturday Richmond

Here is the code and presentation

Title: Speaking at SharePoint Saturday Richmond

Date: Nov 21st 2009

Location: Massey Technology Center on the J. Sargeant Reynolds Parham Campus, Richmond, VA

Topic: Understanding and Programming Features in SharePoint

Details: This session provides an introduction to SharePoint Features. During the session, I will describe what features are, how powerful they are, and provide some practical approaches to using them. The session also covers concepts of Feature Stapling. The target audience for session includes Beginner and Mid level developers.

Thursday, November 5, 2009

Error while deploying using VSEWSS 1.3

Title: Error while deploying using VSEWSS 1.3

Scenario: On my Windows Vista x64 and IIS 7.0, I installed VseWss 1.3 version and tried to use simple out of the box site definition template. When I build the project every thing is fine. However, when I try to deploy the project it gives me the below error.

-------------------------------------------------------------------------

Error 1 The content type text/html; charset=utf-8 of the response message
does not match the content type of the binding (text/xml; charset=utf-8). If
using a custom encoder, be sure that the IsContentTypeSupported method is
implemented properly. The first 1024 bytes of the response were: ' html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "
http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>IIS 7.0 Detailed Error - 500.0 - Internal Server Error</title>
<style type="text/css">
<!--
body{margin:0;font-size:.7em;font-family:Verdana,Arial,Helvetica,sans-serif;background:#CBE1EF;}

code{margin:0;color:#006600;font-size:1.1em;font-weight:bold;}
.config_source code{font-size:.8em;color:#000000;}
pre{margin:0;font-size:1.4em;word-wrap:break-word;}
ul,ol{margin:10px 0 10px 40px;}
ul.first,ol.first{margin-top:5px;}
fieldset{padding:0 15px 10px 15px;}
.summary-container fieldset{padding-bottom:5px;margin-top:4px;}
legend.no-expand-all{padding:2px 15px 4px 10px;margin:0 0 0 -12px;}
legend{color:#333333;padding:4px 15px 4px 10px;margin:4px 0 8px
-12px;_margin-top:0px;
border-top:1px solid #EDEDED;border-left:1px solid #EDEDED;border-right:1px
solid #969696;
border-bottom:1px solid
#969696;background:#E7ECF0;font-weight:bold;f'. 0 0


-------------------------------------------------------------------------

Resolution: After a little bit of googling around I found that the error is related to VseWSS 1.3 version, WCF and IIS 7.0.

So, here is what we need to do:
For Windows Vista:
#1. Under Control Panel > Programs > Programs and Features > Click Turn Windows Features On or Off.
#2. Under Microsoft .NET Framework 3.0, choose Windows Communication Foundation HTTP Activation.
#3. Install the selected features.

Operation aborted (Exception from HRESULT: 0x80004004 (E_ABORT))

Title:Error: Operation aborted (Exception from HRESULT: 0x80004004 (E_ABORT)) or unable to add selected web part(s). Operation aborted.

Scenario: "Every thing was fine until today morning" - that's the kind of surprising face you might have all of a sudden and from no where one of the above errors might appear on the site when ever you try to modify some thing.

Resolution: Any modification is a write operation to the database. Since you might not be able to get more details as you see the above errors, its worth checking some options.

#1. Check the SQL Log File, the Database size and Database Space available.
#2. Check the Log Files. It might be that the log file is full and writes are blocked.
#3. Other most common issue is that there is less space on the drive.

Tuesday, October 20, 2009

Sending Email or SMS using SPAlert ( SPAlertDeliveryChannels )

Title:Sending Email or SMS using SPAlert
Sends notification to a user about the list, list item, document, or document library to which the alert applies via E-mail or SMS.


SPAlert has the property SPAlertDeliveryChannels - an enumaration type that has enum values Email and Sms


Reference : MSDN

SharePoint 2010 Development Tools : SPMetal

Title: SPMetal
SPMetal is a command line tool that generates entity classes that are in turn used in Linq to SharePoint - Microsoft.SharePoint.Linq ( new in SP 2010 ). It is like an interface to connect to the Foundation 2010 Content Databases that enables operations such as add, delete and change items.


SPMetal can be found under the location C:\Program Files\Common Files\Microsoft Shared\web server extensions\14\BIN\
Usage:

SPMetal /web:http://ContosoServer/Marketing /code:MarketingSite.cs

Reference : MSDN

Client API Class Library in SharePoint 2010

Title: SharePoint 2010 Client API
It's not been 1 day before SharePoint SDK Documentation is released on MSDN and already its so compelling to using 2010. Here is some thing very intresting and I am waiting to write code on.


SharePoint Foundation 2010 has a all new class library 'The Client API'. Voila!!! what does that mean... now you can write even better managed client object model for Silverlight and .net in SharePoint 2010. Isnt it cool???


So, here are the available namespaces and class library references:

Microsoft.SharePoint.Client - Core namespace that provides types and members for working with SharePoint Foundation Web sites, list data, and security within a site collection.

Microsoft.SharePoint.Client.Application - Provides types and members that are used for authentication.

Microsoft.SharePoint.Client.Utilities - Provides utility types and members for managing users as principals.

Microsoft.SharePoint.Client.WebParts - Provides types and members for managing Web Parts within Web Part pages.

Microsoft.SharePoint.Client.Workflow - Provides types and members for managing workflow templates and workflow associations.

Reference : MSDN

Monday, October 19, 2009

SharePoint 2010 What's Deprecated?

Title: What's Deprecated?
As many as 190 Types and Methods are deprecated in the new version ( beta ).
you can find the details here.

What's New in SharePoint Server 2010?

Title: SharePoint Server 2010
Some of the new features in SharePoint Server 2010 are listed below:

Business Connectivity Services (BCS)
Enterprise Content Management (ECM)
SharePoint Enterprise Search
PerformancePoint Services
Excel Services
User Profiles and Social Data
Word Automation Services Overview

more information here

What's new in SharePoint Foundation 2010?

Title: Foundation 2010
Foundation 2010 ( next version of WSS 3.0 ) has the following new features

Alerts Enhancements
Business Connectivity Services
Client Object Model
Events Improvements
Microsoft Synch Framework
Mobile Device Development Enhancements
Query Enhancements
Ribbon
Sandboxed Solutions
Service Application Framework
Silverlight Integration and the Fluid Application Model
UI Improvements
Windows PowerShell for SharePoint
Workflow Improvements

more details here

SharePoint 2010 Resources

The much awaited SharePoint 2010 resources can now be obtained from here.

http://blogs.msdn.com/sharepoint/archive/2009/10/19/sharepoint-2010-resources.aspx

Tuesday, October 6, 2009

SPWeb.AvailableContentTypes Vs SPWeb.ContentTypes

Title: SPWeb.AvailableContentTypes Vs SPWeb.ContentTypes


Scenario: Try to get the content types from using both the properties. You might notice that there is no difference. Well then why do we have 2 different properties. Here is the code to get the content types ( notice the comments ) ...

static void GetListTypeID()
{
using (SPSite oSite = new SPSite(@"http://localhost/"))
{
using (SPWeb oWeb = oSite.OpenWeb())
{
//SPContentTypeCollection ctypecoll = oWeb.ContentTypes; // USING CONTENT TYPES
SPContentTypeCollection ctypecoll = oWeb.AvailableContentTypes; // USING AVAILABLE CONTENT TYPES
foreach (SPContentType type in ctypecoll)
{
Console.WriteLine("ID: " + type.Id + " ; Name: " + type.Name);
}
}
}
}




Run the above using either of ContentTypes and AvailableContentTypes. You will see that the result is same.

From MSDN the difference is

The ContentTypes property returns only the content types that exist on the current Web site, not all content types in the current scope. Use the AvailableContentTypes property to return all content types in the current scope, including those of any parent Web sites.

Though it helped me to understand I couldnt get the real essence of it. So, the intresting concept is that AvailableContentTypes is READONLY. You cannot add a new ContentType by using AvailableContentTypes collection.

** CORRECTIONS **
My bad... Some mis-interpretation with my wordings above. The above code as is executed at Site Collection level gives the same results. As mentioned above from MSDN AvailableContentTypes gives information including subsite content types. However, my point is to bring out which one should be used to create new content types ( ContentType ) and which one is read-only ( AvailableContentTypes ). Hope you got the point right.

Monday, October 5, 2009

Programmatically Get Content Types

Title: You might want to get all the content types on a given site

Code:

static void GetListTypeID()
{
using (SPSite oSite = new SPSite(@"http://localhost/"))
{
using (SPWeb oWeb = oSite.OpenWeb())
{
SPContentTypeCollection ctypecoll = oWeb.ContentTypes;
foreach (SPContentType type in ctypecoll)
{
Console.WriteLine("ID: " + type.Id + " ; Name: " + type.Name);
}
}
}
}

Friday, September 25, 2009

One or more features must be turned on before this feature cab be activated

Title: One or more features must be turned on before this feature cab be activated

Scenario: Trying to activate 'Office SharePoint Server Publishing' feature on the Site Features of the site.

Solution: Activate the 'Office SharePoint Server Publishing Infrastructure' feature at the site collection level first before trying the scenario.

Create Site Collection in a specific Content Database

Title: Create Site Collection in a specific Content Database

Scenario: My previous post on the same topic are some ways to create site collections in the specific content database. Programmatically we can also do it as mentioned in this blog post done by my friend Sandeep. So I kind of put them all in all and created a simple console application to create site collection in a specific content database.

Download the file and try for yourself.

Usage: use the command as show below.


Wednesday, September 23, 2009

Getting context using RunWithElevatedPrivileges

Title: Getting context using RunWithElevatedPrivileges


Scenario: Have you ever tried creating the SPSite and SPWeb context inside the RunWithElevatedPrivileges context? If you have done so, then you must have noticed that the context user is still the logged in user and is not elevated to the app_pool identity.
To get the right context, use the code as shown below.


Code:

SPSite siteColl = SPContext.Current.Site;
SPWeb webSite = siteColl.OpenWeb();

SPSecurity.RunWithElevatedPrivileges(delegate()
{
using (SPSite site = new SPSite(siteColl.ID))
{
using (SPWeb web = site.OpenWeb(site.ID))
{
// DO SOME THING IMP HERE
}
}
});

How to create Site Collection in a specific Content Database?

Title: How to create Site Collection in a specific Content Database?

Scenario:
We often have this requirement of creating sites collections in a specific content database instead of going into one of the available content databases. So, here are few available ways that can be considered. Every thing has its own disadvantages. So, pick the one which suits you the best.

Solution:
Option # 1 : While creating the new content database from CA you can set the options in Database Capacity Settings to limit the number of sites along with Warning. However it allows always 1 extra space for one more C-DB. So, you need proper planning well before for it. Ofcourse you can always go and increase it. So it might not be good working idea every time.





Option # 2 : As posted in my previous post use STSADM createsiteinnewdb option. Problem with this model is that you cannot create more than 1 site into the same CDB.


Option # 3 : Moving Site Collections between Content Databases


Per say if the site collection is created in an unwanted CDB, then you can move the site collection to the required CDB using the below statements. However, the issue with this model is you may not have the freedom to do it on production servers. So make sure you script it out properly and provide it to the Administrators.


STSADM.EXE -o enumsites -url http://mysiteiwantetomove > sites.xml



Open the sites.xml file and edit the file so that you would have only those site listing that you want to move.

STSADM.EXE -o mergecontentdbs -url http://mysiteiwantetomove -sourcedatabase
[databasename] -destinationdatabase [databasename] -operation 3 -filename sites.xml



Option # 4 : Take CDB's to offline mode


Go to CA > AM > CDB's and edit.
You can take all other CDB's to offline mode except the one you want to create site collections under. That way, your new site collection will be created in the CDB available in ready mode. Once you create the site collection, make sure you bring back the other CDB's to ready mode.

Saturday, September 19, 2009

Get all the sub sites under the current site

Scenario:
You want to get all the sub sites under a given site collection including sub sites under sub sites.
Scenario:
Use site.AllWebs to get the entire collection as shown below.
Code:

void GetAllSitesUnderSiteCollection(string siteUrl)
{
using (SPSite site = new SPSite(siteUrl))
{
foreach (SPWeb web in site.AllWebs)
{
Console.WriteLine(web.Title + " ~ " + web.Url);
}
}
}

Create Site in New Database using stsadm (createsiteinnewdb)

Title: Create Site in new database using createsiteinnewdb
Code:

stsadm -o createsiteinnewdb -url http://yourownurl/ -owneremail owner@emailid.com -sitetemplate sts#1 -title "My Site Title" -databasename Create_Under_This_DB -ownerlogin NTLogin\Admin

Programmatically Delete Site Collection

Title: Programmatically Delete Site Collection
Code:

void DeleteSiteCollection(string requestUrl, string siteUrl)
{
SPSite site = new SPSite(requestUrl);
SPWeb web = null;
try
{
SPWebApplication webapp = site.WebApplication;
web = site.OpenWeb();
SPSiteCollection spSites = webapp.Sites;
webapp.Sites.Delete(siteUrl);
}
finally
{

}
}

Programmatically Create Site Collection

Title:Programmatically Create Site Collection
Code:

void CreateSiteCollection(string requestUrl, string siteUrl, string title, string description, uint lcid, string webTemplate, string ownerLogin, string ownerName, string ownerEmail)
{
SPSite site = new SPSite(requestUrl);
SPWeb web = null;
try
{
SPWebApplication webapp = site.WebApplication;
web = site.OpenWeb();
SPSiteCollection spSites = webapp.Sites;
webapp.Sites.Add(siteUrl, title, description, lcid, webTemplate, ownerLogin, ownerName, ownerEmail);
}
finally
{

}
}

Thursday, August 6, 2009

Hide or Show Quick Launch Bar

Title: Hide or Show the Quick Launch Bar

Scenario: Our custom master page (xyz.master) overrides the default.master page. The requirement was not to show the left navigation / quick launch menu on the left hand side. However, some site collections that inherit our xyz.master might need the feature of having quick launch visible.

Preface: There are many ways to do it. You can write code that behave intelligently to handle this and so on and so forth. But the situation could be - it is already hosted and may not have room for a binary drop or feature stapling. Well what I did?

At first place, the quick launch menu can be hidden using the below CSS code

Code:

<style>
.ms-navframe { display:none; }
</style>

So to enable it back, all we need to do is to set the display property to 'block' instead.

I added a content editor webpart and add the below code to the page.

<style>
.ms-navframe { display:block; }
</style>

Since a CEWP can handle code that of script and styles, it can override the master page css and displays the quick launch.

Wednesday, July 22, 2009

SharePoint Site Backup and Restore using STSADM

Scenario: Backup sitecollection and restore it on a different server or same server.

Preface: Lets build some simple script (batch) files here. First declare the constants. Notice the BACKUPFILENAME variable. That would build the file name as YYYY_MM_DD_BACKUP.BAK

Code:

@SET STSADM="c:\program files\common files\microsoft shared\web server extensions\12\bin\stsadm"
@SET MAINSITEURL="http://servername"
@SET BACKUPFILENAME="C:\SiteBackUp\%date:~10,4%_%date:~4,2%_%date:~7,2%_backup.bak"

Backup Commands: Before you take the backup, ensure the Site has 'none' lock. However, when you are ready to run the backup... make sure you make the site lock to 'readonly' so that no further changes can occur.

@echo off
Echo ------------------------------------------------------------------

Echo Getting Site Lock
stsadm -o getsitelock -url %MAINSITEURL%

Pause

Echo Setting Site Lock to ReadOnly
stsadm -o setsitelock -url %MAINSITEURL% -lock readonly

Echo Backing up the top level site
stsadm -o backup -url %MAINSITEURL% -filename %BACKUPFILENAME% -overwrite

Echo Setting Site Lock to None
stsadm -o setsitelock -url %MAINSITEURL% -lock none

Echo ------------------------------------------------------------------
Pause please press any key to continue...

Restore Commands: Use the below script to restore the backed up site onto the new site collection on a new machine.


Echo Getting Site Lock
stsadm -o getsitelock -url %MAINSITEURL%

Pause
@echo off
Echo ------------------------------------------------------------------

Echo Setting Site Lock to none
stsadm -o setsitelock -url %MAINSITEURL% -lock none

Echo Restoring the top level site
stsadm -o restore -url %MAINSITEURL% -filename %BACKUPFILENAME%

Echo Setting Site Lock to None
stsadm -o setsitelock -url %MAINSITEURL% -lock none

Echo ------------------------------------------------------------------
Pause please press any key to continue...



Output: In case the target site does not exist Restore commands would create a new site collection (if it were a different server). If restoring on the same server, you have to use '-override' parameter or have to create a new content database for that Site Collection and then restore.

Ensuring SharePoint Success

Dux Raymond will be hosting a mentoring workshop "Ensuring SharePoint Success: How to Effectively Deliver the Promise of SharePoint" on August 19-21, 2009. In this unique, one time event, he'll be joining by leading SharePoint thought leaders (Paul Culmsee, Andrew Woody and Ruven Gotz) in Organizational Change, Project Management, Requirements Development and Agile Methodology from around the world mentoring you to make sure you can deliver SharePoint success. Not only will they teach key concepts and theories, they'll provide real-world templates, checklists, project artifacts and provide group + 1 on 1 mentoring sessions with the participants!


Check out further details here.

RightsSensitiveVisibilityHelper UserHasRights

Scenario: Find whether the current user has permissions for a specified SPList object

Output:
true if the current user has permissions for the object; otherwise, false.

Code:

public static bool UserHasRights (
PermissionContext permissionContext,
SPBasePermissions permissions,
PermissionMode permissionMode,
SPList contextList
)

Where,
permissionContext: value that indicates the context object to which a permission mask is applied.

permissions: An SPBasePermissions value that specifies the built-in permissions available in

permissionMode: A PermissionMode value that specifies whether the user must have all of the rights specified in the permission mask to view a link, or only one of the rights specified in the permission mask.

contextList: The SPList object to evaluate.

Tuesday, July 14, 2009

Adding and Removing a button to the Ribbon ( SharePoint 2010 )

*** Please view the disclaimer before you proceed ***

Scenario: Adding and Removing a button on the Ribbon. You can define the location on the Ribbon where you want the button to appear. Follow the below method to add a new button / remove the button to the Library tab in the Actions group for a document library.

How-To:

    1. Create a folder under 14 hive\Template\Features (SharePoint 2010 will have 14 hive similar to that of 12 in WSS / MOSS 2007) RibbonButton
    2. As seen in the previous post create the feature.xml
    3. Create a blank xml file, manifest.xml and add the below content (Adding Button) to it and Save it.
    4. Deploy the customization using Windows PowerShell as shown in my previous blog.
    5. Test it by navigating to the document library in your site / sub site and clicking on the library tab > Actions group > New Button button.
    6. To remove the button replace the content in the manifest.xml with the Removing Button content mentioned below.

Adding Button:



<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<CustomAction Id="Ribbon.Library.Actions.AddAButton"
Location="ViewToolbar"
RegistrationId="101"
RegistrationType="List"
Title="Add a Ribbon Button">
<CommandUIExtension>
<CommandUIDefinitions>
<CommandUIDefinition
Location="Ribbon.Library.Actions.Controls._children">
<Button Id="Ribbon.Library.Actions.NewRibbonButton" Command="NewRibbonButtonCommand"
Image16by16="/_layouts/images/FILMSTRP.GIF"
Image32by32="/_layouts/images/PPEOPLE.GIF"
LabelText="New Button"
TemplateAlias="o2" />
</CommandUIDefinition>
</CommandUIDefinitions>
<CommandUIHandlers>
<CommandUIHandler
Command="NewRibbonButtonCommand"
CommandScript="javascript:alert('This is a new button!');" />
</CommandUIHandlers>
</CommandUIExtension>
</CustomAction>
</Elements>

// Image16by16 and Image32by32 are part of SharePoint 2010

Removing Button:



<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<HideCustomAction Id="RemoveRibbonButton"
Location="CommandUI.Ribbon.Library.Actions.ConnectToClient">
</HideCustomAction>
</Elements>

Technorati Tags: ,

Customizing and Deploying Ribbon in SharePoint 2010

*** Please view the disclaimer before you proceed ***

Introduction: You might have seen in the sneak peek and beta screens of Office 2010 the new Ribbon pattern / interface / control. This post would give details about how to customize and deploy the same using Windows Power Shell.

How to: A sample feature could resemble the following:

<?xml version="1.0" encoding="utf-8" ?>
<Feature Id="FeatureId"
Title="Name of the Feature"
Description="Description of the Feature."
Version="1.0.0.0"
Scope="Web"
xmlns="http://schemas.microsoft.com/sharepoint/">
<ElementManifests>
<ElementManifest Location="manifest.xml" />
</ElementManifests>
</Feature>

To deploy and enable it use the following commands:

Install-SPFeature FeatureId Enable-SPFeature FeatureId -Url http://server/site/subsite


Technorati Tags: ,

SharePoint Products and Technologies: 2010 (Tech Preview) Developer Documentation

Here is the link. It has got the Reference Document help file and how to customize the new ribbon control.

Help file contains details of lot of new web controls that you might want to see when compared with MOSS 2007.

Monday, July 13, 2009

SharePoint 2010 – Preliminary System Requirements - Getting Ready

Gear up for the SharePoint 2010 now. You might want to check the following and take advantage of the forth coming SharePoint 2010 Services.

Hardware:

    • Plan for 32bit to 64bit upgrade. SP 2010 has 64bit flavor only.
    • SP 2010 needs SQL 2K8 or SQL 2K5 running on 64 bit. Which means, you might want to considering upgrading your SQL box too.
    • SP 2010 will need Windows 2008 Server or above to run.
    • Make sure your development environment is also upgraded to 64bit.

Service Packs:

    • If you are planning to upgrade from MOSS 2007 or WSS 3.0, first deploy your existing environment with SP2 and then upgrade to SP 2010.
    • Run the Upgrade Checker Tool that’s included in SP2 which might bring upfront notice of possible issues during or upon upgrade.

Development:

    • Consider migrating to Visual Studio 2010 (pretty good migration and new tools available)
    • Watch for deprecated API’s
    • New deployment and packaging available with VS 2010 coming along.
    • Learn LINQ, entity models and Silverlight since these are supported in SP 2010.

Browser Compatibility:

    • IE > 6.0 is a mandate, which means you cannot use IE 6.0.
    • Fire Fox 3.x is supported.
Technorati Tags:

SharePoint 2010

Disclaimer:

Hi All,

Very soon I will start blogging about SharePoint 2010 a.k.a SharePoint Services “14”. Well since we are still talking about the beta version coming down during October this year, what ever is written in the blog might change substantially prior to the final commercial release. Also you cannot test them until you have either final product or beta or any prior tech preview releases (if any) that Microsoft makes. The risks associated with the implementation of my writings are purely users and solely its users decision and discretion in using so.

regards,
Srini Sistla

SharePoint 2010 Sneak Peek

Here is the link to the SharePoint 2010 Sneak Peek. Cant wait longer to get hands on :-)... Waiting to see if I can get the tech preview.

Friday, July 10, 2009

SilverLight 3.0 Released

Today SilverLight 3.0 and Microsoft Expression 3.0 released. Details are here.

What’s new in SilverLight 3.0 are here.

Technorati Tags:

Thursday, July 9, 2009

RSS / Atom Aggregator WebPart - Syndication using WCF

Preface: In my previous post, I wrote about the RSS Aggregator Webpart. That version of code used XMLDom model. However, in .NET 3.5 we have syndication classes available and you can see how reading RSS / Atom feeds have become so easy. This supports Atom 1.0 and RSS 2.0 versions.

Since the process is same, you can pass multiple feed url’s and make it aggregator too.

Assembly Reference: System.ServiceModel.Syndication

Solution:

public void GetSyndication(string url)
{
SyndicationFeed feed = SyndicationFeed.Load(XmlReader.Create(url));
if (null != feed)
{
foreach (SyndicationItem item in feed.Items)
{
//Link to the Post - item.Links[0].Uri.AbsoluteUri.ToString()
//Title of the Post - item.Title.Text
//Description - item.Summary.Text
}
}
}

Most of the time, you will end up querying either of Atom / RSS formats and you never know which one is the input. So, I kind of had a check point to validate the input formats. If one of the conversion fails, its obviously the other. Well here is the full code.


Your entry point would be GetSyndicationFeed Method if you dont know what's the incoming feed. However, if you know the feed type then you can directly call either the GetRSSFeedString method or GetAtomFeedString method directly.

public string GetSyndicationFeed(string url, string type)
{
if (string.IsNullOrEmpty(url)) return string.Empty;

string ret = string.Empty;
switch (type.ToLower())
{
case "rss":
ret= GetRSSFeedString(url);
break;
case "atom":
ret= GetAtomFeedString(url);
break;
case "": // Acts as a validator
try {
Rss20FeedFormatter rss = new Rss20FeedFormatter();
rss.ReadFrom(XmlReader.Create(url));
ret= GetRSSFeedString(url);
}
catch (XmlException exml){
ret= GetAtomFeedString(url);
}
break;
}
return ret;
}

public string GetRSSFeedString(string url)
{
StringBuilder sb = new StringBuilder();
Rss20FeedFormatter rss = new Rss20FeedFormatter();

try
{
rss.ReadFrom(XmlReader.Create(url));
}
catch (XmlException exml)
{
// Log it.
}

if (null == rss.Feed) return string.Empty;

foreach (SyndicationItem item in rss.Feed.Items)
{
// item.Links[0].Uri.AbsoluteUri.ToString() // - URL link to the post
// item.Summary.Text.ToString() // - Description or Summary of the post
// item.Title.Text // - Title of the post
}

return sb.ToString();
}

public string GetAtomFeedString(string url)
{
StringBuilder sb = new StringBuilder();
Atom10FeedFormatter atom = new Atom10FeedFormatter();

try
{
atom.ReadFrom(XmlReader.Create(url));
}
catch (XmlException exml)
{
// Log it.
}

if (null == atom.Feed) return string.Empty;

foreach (SyndicationItem item in atom.Feed.Items)
{
// item.Links[4].Uri.AbsoluteUri.ToString() // - URL link to the post
// ((System.ServiceModel.Syndication.TextSyndicationContent)(item.Content)).Text // - Description or Summary of the post
// item.Title.Text // - Title of the post
}

return sb.ToString();
}

Technorati Tags: ,,,,

Wednesday, July 8, 2009

Scheduling a SharePoint Backup

Scenario: Unfortunately as in the previous version, MOSS 2007 also doesn't have a tool for scheduling backups.

Solution: Command-Line backup tools – The stsadm.exe enables sharepoint admins to backup site collections using the command line and makes it easier to restore site collection (or a site).

Usage:
stsadm –o backup –url <url> –filename <filename> [-override]

for example:

stsadm –o backup –url http://myserver/sites/ –filename c:\mybackups\


Catastrophic backup: The stsadm utility now lets you do a full SP backup as you would with a CA Page.


To issue a full or differential backup use the format

stsadm –o backup –directory <unc path> –backupmethod <full | differential> [-item<created path from tree>] [-%<int between 1 and 100>] [-backupthreads<int between 1 and 10>] [-showtree] [-quite]


for example: (to back up entire SP Farm)

stsadm –o backup – directly \\backups\sharepoint –backupmethod full 


Technorati Tags: ,

SharePoint Versions and Licenses

Currently in use in market (not including the previous versions):

Windows SharePoint Services 3.0 – Windows Server CAL or Windows External Connector

Microsoft Office SharePoint Server 2007 Standard – Windows CAL + MOSS Std CAL or Core CAL

Microsoft Office SharePoint Server 2007 Enterprise – Windows CAL + MOSS Std CAL or Core CAL + MOSS Ent CAL or eCAL

Microsoft Office SharePoint Server 2007 for Internet Sites – Windows External Connector + MOSS for Internet Sites (no CALs)

Technorati Tags: ,

Interesting Fact

Certain files in the SharePoint installation folders contain OWS or STS. These stand for Office Web Server and SharePoint Team Services respectively. You also might want to know what VTI stands for as in VTI_BIN. It’s Vermeer Technologies Inc., which was acquired by Microsoft. Vermeer was the original developer of FrontPage.

Tuesday, July 7, 2009

Programmatically Get SPList Attachments

Here is the code snippet to get the Attachments of a given SPList. You can modify the code to return a collection instead.

public void GetListAttachments(string site, string listName)
{
//StringBuilder sAttNames = new StringBuilder();
using (SPSite oSite = new SPSite(site))
{
using (SPWeb oWeb = oSite.OpenWeb())
{
SPList oList = oWeb.Lists[listName];

SPListItemCollection oListItems = oList.Items;
foreach (SPListItem item in oListItems)
{
SPAttachmentCollection collAttachments = item.Attachments;

if (collAttachments.Count <= 0) return string.Empty;

foreach (var attachment in collAttachments)
{
//sAttNames.Append(attachment.ToString());
}
}
}
}
//return sAttNames.ToString();
}


Monday, July 6, 2009

Programmatically getting SharePoint Site Columns

Here is a simple code snippet of how to get all the available Site Columns under a given site.


public string GetSiteColumns(string site)
{
string sRet = string.Empty;
using (SPSite oSPSite = new SPSite(site))
{
using (SPWeb oSPWeb = oSPSite.OpenWeb())
{
foreach (SPField field in oSPWeb.Fields)
{
if(null == field) return null;

//if(field.Group.ToLower() == "srini")
//{
sRet += field.Title.ToString() + ",";
//}
}
}
}
return sRet;
}

SharePoint Site Columns – an Introduction

Scenario: We would like to ‘re-use’ functionalities as much as we can every where. So why not a column that can be reused in every list or on a list i want in specific?

Introduction: Site Columns are ‘meta-data fields’ that you can create and then use them any where you want under any list.

How To: You can create a site column by accessing the page under Site Settings > Site Columns or from the page ‘_layouts/mngfield.aspx’.

Now, you can create the Column and choose type that are available under the New Site Column creation wizard. Also, you can specify to add it under a specific group or create a new group on the fly.

Once you create the column, it is now accessible from any list when you select the option ‘Add from existing site columns’ option.

Interesting: Ok! the beauty of this is… when you update the Site Column values, the column values on your inherited list are automatically updated (default is ‘Auto Yes’). Well, when you delete the Site Column… the inherited list will not lose any data nor the column by itself.

You see what’s happening? Guess why? :-)

Asynchronous Pages in ASP.NET 2.0

Scenario: When ASP.NET receives a page request, it is basically a thread from the thread pool and then considered as a request thread. To understand it simply, consider that the life cycle is Synchronous. Any intermediate Async process is considered as breaking the line of process since Async must run on a separate thread from there onwards. Situations some time tend us to use some process and we will be immediately thrown with the error below.

Error: “Asynchronous operations are not allowed in this context. Page starting an asynchronous operation has to have the Async attribute set to true and an asynchronous operation can only be started on a page prior to PreRenderComplete event”

Support: ASP.NET 1.1 version does not support it OOB but it has a back door entry to do it.

However in ASP.NET 2.0, its a very simple attribute setting on the page directive.

<% Page Async=”true”…...


Consider that the situation further demands that you need to set it on run time and not on design time on page.



So, one has to subscribe to the below event and do the rest of the magic.



AddOnPreRenderCompleteAsync (
new BeginEventHandler(MyBeginMethod),
new EndEventHandler (MyEndMethod)
);


for more detailed information, view this blog

Saturday, July 4, 2009

Merging multiple SPList and binding to SPGridView

Scenario: Many instances it so happens that we have to read multiple list and merge them together and then bind the merge list to SPGridView. Here is one example of how to implement it. This is a vanilla code which works great. But its at your discretion that you can further simplify and refactor it.

Implentation:

I used 2 classes here. Again use your own ideas how you want to make it more better.
Before we start, I created 2 custom list (1 with name 'Srini Test' and other with 'New List') with columns added as 'URL' and 'Description' along with 'Title' (default OOB).

Util Class:
---------------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.Data;
using System.Web;
using Microsoft.SharePoint;
namespace BlogIt
{
public class Util
{
public DataTable GetDataTableFromList(string site, string web, string listname)
{
DataTable dt = null;
using(SPSite oSPSite = new SPSite(site))
{
using(SPWeb oSPWeb = oSPSite.OpenWeb())
{
SPList oList = (SPList)oSPWeb.Lists[listname];
dt = oList.Items.GetDataTable();
}
}
return dt;
}
}
}

---------------------------------------------------------------------------
Webpart Class:
---------------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.Data;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using Microsoft.SharePoint.WebControls;
namespace BlogIt
{
public partial class _Default : System.Web.UI.Page
{
Util oUtil = new Util();
SPGridView oSPGridView = new SPGridView();
protected override void OnInit(EventArgs e)
{
oSPGridView.ID = "_spgv1";
oSPGridView.AutoGenerateColumns = false;
BuildGridColumns();
base.OnInit(e);
}
private void BuildGridColumns()
{
BoundField bfTitle = new BoundField();
bfTitle.HeaderText = "Title";
bfTitle.DataField = "Title";
oSPGridView.Columns.Add(bfTitle);
BoundField bfURL = new BoundField();
bfURL.HeaderText = "URL";
bfURL.DataField = "URL";
oSPGridView.Columns.Add(bfURL);
}
protected override void CreateChildControls()
{
this.Controls.Add(oSPGridView);
base.CreateChildControls();
}
protected void Page_Load(object sender, EventArgs e)
{
DataTable oDt1 = oUtil.GetDataTableFromList("http://localhost:81/", string.Empty, "Srini Test");
DataTable oDt2 = oUtil.GetDataTableFromList("http://localhost:81/", string.Empty, "New List");
oDt1.Merge(oDt2);
oSPGridView.DataSource = oDt1;
oSPGridView.DataBind();
}
public override void VerifyRenderingInServerForm(Control control)
{

}
}
}

---------------------------------------------------------------------------

Friday, July 3, 2009

Stsadm command for Switching Authentication Mode - Access Denied Issue

Last week we used the below command and encountered an issue that the conversion was unsuccessful. However, on CA it was showing that it converted correctly.

STSADM -o authentication -url -type forms -membershipprovider -roleManager

Now, when we access the site it was giving AccessDenied error.

After our analysis, we figured out that the Database was not correctly updated with the job.

So we did 2 steps:

#1: From CA, we changed the authentication mode to Windows - Successful. We changed again to Forms - Failed.
#2: Now we are our fav command : ststadm -o execadmsvcjobs

Success. Now the mode is correctly changed as the job status is complete.

Thursday, July 2, 2009

Using Disposable Objects (SharePoint Best Practices)

Question:
Why do we need to dispose objects we create?
Most often we tend to write Unmanaged code inside managed code. Managed Objects created from such Managed classes as SPSite and SPWeb
has very little to do with the unmanaged code sitting inside their boundary. Now, when you compare this size of the managed part is considerably
lesser than that of the unmanaged part, GC would ignore mostly and doesnt clear the objects created underneath. This results in memory leaks, your application performs slow, and you have a big laundry list of items to complain etc etc and etc.

Solution:
3 suggested best practices are as below:

#1. Use Dispose or Close Methods - Technically both are same, just that Dispose again calls Close internally.
#2. Using Clause - Automatic Dispose
#3. Use Try, Catch and Finally Block - Manual Force - Best method as I feel, since it gives you the power of catching the exceptions if any.


Examples:


"using Clause"
 
String str;

using(SPSite oSPsite = new SPSite("http://server"))
{
using(SPWeb oSPWeb = oSPSite.OpenWeb())
{
str = oSPWeb.Title;
str = oSPWeb.Url;
}
}

In the above example though SPSite is the parent of SPWeb and takes care of disposing the SPWeb object (incase you havent auto or forced it), its good to also have the using clause for the SPWeb object too.


"Using Try, Catch and Finally Blocks"
 
String str;
SPSite oSPSite = null;
SPWeb oSPWeb = null;

try
{
oSPSite = new SPSite("http://server");
oSPWeb = oSPSite.OpenWeb(..);

str = oSPWeb.Title;
}
catch(Exception e)
{
//Handle exception, log exception, etc. // NEVER EVER LEAVE THIS BLOCK EMPTY.
}
finally
{
if (oSPWeb != null) // GOOD PRACTICE TO CHECK IF OBJECT IS NOT NULL BEFORE DISPOSING
oSPWeb.Dispose();

if (oSPSite != null) // GOOD PRACTICE TO CHECK IF OBJECT IS NOT NULL BEFORE DISPOSING
oSPSite.Dispose();
}



for more information on Best Practices, follow this link here.

Sunday, June 14, 2009

Programmatically Adding SharePoint Group and Quick Add Group

Simple way to add a new custom group or custom quick add group programmatically.

Elements File Modification
Add the below 2 lines of code to your elements file under Elements > Module > File

 
<?xml version="1.0" encoding="utf-8" ?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<Module Name="AltsisWebParts" Url="_catalogs/wp">
<File Url="Srini.webpart" Type="" >
<Property Name="Group" Value="AltsisGroup" />
<Property Name="QuickAddGroups" Value="AltsisGroup" />
</File>
</Module>
</Elements>

Friday, June 12, 2009

Simple PunchIn PunchOut program using SPList



Scenario :The below code demoss a simple PunchIn / PunchOut program uisng SPList. Also depicts the Inserting data to sharepoinnnnnnt list using webpart. First step, see the below image output.
Steps :Step 1 : Create a custom list aaand add 3 columns to it. Username, InTime, OutTime.
Step 2 : Use the below code
Step 3 : Deploy the webpart and add the webpart to ur page.
Code :
  
using System;
using System.Runtime.InteropServices;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Serialization;
using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;
using Microsoft.SharePoint.WebPartPages;
namespace Punch
{
[Guid("c123a186-3795-4eda-b655-62c4dcedbeff")]
public class PunchTime : System.Web.UI.WebControls.WebParts.WebPart
{
private const string punchListName = "punchlist";
public PunchTime()
{
}
protected override void CreateChildControls()
{
base.CreateChildControls();
Button button = new Button();
button.Text = "Punch In";
button.Click += new EventHandler(button_Click);
this.Controls.Add(button);
}
void button_Click(object sender, EventArgs e)
{
SaveTimeLogs();
}
void SaveTimeLogs()
{
SPWeb web = SPContext.Current.Web;
SPUser user = web.CurrentUser;
SPListItemCollection listItemCol = web.Lists[punchListName].Items;
SPListItem item = listItemCol.Add();
item["UserName"] = user.Name.ToString();
item["InTime"] = DateTime.Now.ToShortTimeString();
item.Update();
}
}
}

Wednesday, May 27, 2009

RSS Aggregator Web Part

After a long search on internet, I finally thought I have to write this RSS Aggregator Web Part that works for both Atom and RSS Formats.

First, I would like to give credit to this post by Sahil Malik which gave me the kick start.

Next, read my previous blog to understand the differences between RSS and Atom XML structure as I will be using the base of them to retrieve both blogger posts.

Now that we have our basic understanding lets jump in to the code. I am using the same css class names here since I wanted to mimic the same way as the outbox RSS Webpart. You can have your own incase you need.

We will be using 3 classes here; 1. Webpart Class, 2. Class for RSSFeed 3. Class for RSSItem and 1 JS file. Ofcourse, this code is in working condition, however its not clean. You might want to look at the redundant variable declarations.

JS: _____________________________________________________________
 
<script type="text/javascript">
function switchMenu(obj) {
var el = document.getElementById(obj);
if (el.style.display != 'none') {
el.style.display = 'none';
}
else {
el.style.display = '';
}

CollapseAllDivs(el);
}

function CollapseAllDivs(sDiv) {
var rollUpContainer = document.getElementById('rollUpContainer');
var div = rollUpContainer.getElementsByTagName('div');
for(i = 0; i < div.length; i++) {
if (div[i].id.match("rssAgg") != null) {
var getDiv = document.getElementById(div[i].id);
if (sDiv.id != getDiv.id) {
getDiv.style.display = 'none';
}
}
}
}

</script>

Variable Declarations: _______________________________________________
 
private string rssUrl;
private string feedName;
private const string constDefFeedLimitValue = "5";
private string feedLimit = constDefFeedLimitValue;
private int feedLmt;

WebPart: ________________________________________________________
 
public class RssFeedAggregator : System.Web.UI.WebControls.WebParts.WebPart
{

private string rssUrl;
private string feedName;
private const string constDefFeedLimitValue = "5";
private string feedLimit = constDefFeedLimitValue;
private int feedLmt;

public RssFeedAggregator()
{
this.ExportMode = WebPartExportMode.All;
}

protected override void RenderContents(System.Web.UI.HtmlTextWriter writer)
{
try
{
feedLmt = Convert.ToInt32(feedLimit);
}
catch (Exception)
{
feedLmt = 0;
}
RssFeed feed = new RssFeed(rssUrl);
feed.Sort(delegate(RssItem r1, RssItem r2)
{
return r2.PubDate.CompareTo(r1.PubDate);
});

int i = 0;

string parameterToken;

writer.Write("<div id=\"rollUpContainer\">");
foreach (RssItem singleRssItem in feed)
{
if (i < feedLmt)
{
parameterToken = "rssAgg" + i;

writer.Write("<div id=\"rollUp\" class=\"slm-layout-main\">");
writer.Write("<table width=\"100%\">");
writer.Write("<tr>");
writer.Write("<td width=\"100%\" align=\"left\">");
writer.Write("<table width=\"100%\">");
writer.Write("<tr><td width='100%' class=\"groupheader item medium\">");
writer.Write("<a href='" + singleRssItem.BlogLink.ToString() + "' target='_blank'>" + singleRssItem.BlogTitle + "</a>");
writer.Write("</td>");
writer.Write("</tr>");
writer.Write("<tr><td width='100%' class=\"item link-item\">");
writer.Write("<a href=\"javascript:switchMenu('" + parameterToken + "');\">" + singleRssItem.Title + "</a>");
writer.Write("</td>");
writer.Write("</tr>");
writer.Write("</table>");
writer.Write("</td>");
writer.Write("</tr>");
writer.Write("</table>");
writer.Write("</div>");

if(i > 0)
writer.Write(string.Format(@"<div id='{0}' style='display:none'>", parameterToken));
else
writer.Write(string.Format(@"<div id='{0}'>", parameterToken));

writer.Write("<table><tr><td><div class=\"description\">");
writer.Write(singleRssItem.Body);
writer.Write("</div></td></tr>");

writer.Write("</table>");

writer.Write("</div>");

i++;
}
}
writer.Write("</div>");
}

public string FeedName
{
get
{
return feedName;
}
set
{
feedName = value;
}
}

[WebBrowsable(true),
Personalizable(true),
Category("RSS Properties"),
DisplayName("RSS Feed Url(s)"),
WebDisplayName("RSS Feed Url(s)"),
Description("Use ';' Character For Multiple Feed(s)")]
public string FeedURL
{
get
{
return rssUrl;
}
set
{
rssUrl = value;
}
}

[WebBrowsable(true)]
[Personalizable(true),
Category("RSS Properties"),
DisplayName("Feed Limit"),
WebDisplayName("Feed Limit"),
Description("Feed Limit"),
DefaultValue(constDefFeedLimitValue)]
public string FeedLimit
{
get
{
return feedLimit;
}
set
{
feedLimit = value;
}
}

}

RSSFeed Class: ___________________________________________________________
 
internal class RssFeed : List<RssItem>
{
private XmlDocument xDoc;

internal RssFeed(string RssURL)
{

if (RssURL == null)
{
this.Add(new RssItem());
}
else
{
string[] rssUrlsArray = RssURL.Split(new char[] { ';' });
foreach (string url in rssUrlsArray)
{

try
{
xDoc = new XmlDocument();
XmlTextReader xRead = new XmlTextReader(url);
xDoc.Load(xRead);

if (IsRss(xDoc))
ReadRssFeed(xDoc);
else
AtomFeed(xDoc);

}
catch (Exception)
{
this.Add(new RssItem());
}
}
}
}

internal bool IsRss(XmlDocument xDoc)
{
XmlNodeList xNodes = xDoc.GetElementsByTagName("rss");
if (xNodes.Count > 0)
return true;
else
return false;

}

internal void ReadRssFeed(XmlDocument rssDoc)
{

string blogTitle = string.Empty;
string blogLink = string.Empty;

XmlNodeList xNodesHeader = rssDoc.SelectNodes("./rss/channel");
foreach (XmlNode xNode in xNodesHeader)
{
blogTitle = HttpUtility.HtmlEncode(xNode.SelectSingleNode("./title").InnerText);
blogLink = xNode.SelectSingleNode("./link").InnerText;
}

XmlNodeList xNodes = rssDoc.SelectNodes("./rss/channel/item");
foreach (XmlNode xNode in xNodes)
{
this.Add(new RssItem(xNode, blogTitle, blogLink));
}
}

internal void AtomFeed(XmlDocument atomDoc)
{
string blogTitle = string.Empty;
string blogLink = string.Empty;

XmlNodeList xNodesHeader = atomDoc.GetElementsByTagName("feed");
foreach (XmlNode xNode in xNodesHeader)
{
if (xNode["title"] != null)
blogTitle = HttpUtility.HtmlEncode(xNode["title"].InnerText);

if (xNode["link"] != null)
blogLink = xNode["link"].InnerText;

}

XmlNodeList xNodes = atomDoc.GetElementsByTagName("entry");
foreach (XmlNode xNode in xNodes)
{
this.Add(new RssItem(xNode, true, GetHrefLink(xNode), blogTitle, blogLink));
}

}

internal string GetHrefLink(XmlNode xNode)
{
string ret = string.Empty;

for (int iCount = 0; iCount < xNode.ChildNodes.Count; iCount++)
{
if (xNode.ChildNodes[iCount].Name.ToLower() == "link")
{
if (xNode.ChildNodes[iCount].Attributes["rel"].Value.ToLower() == "alternate")
{
ret = xNode.ChildNodes[iCount].Attributes["href"].Value.ToString();
}
}
}

return ret;
}
}

RSS Item Class: ____________________________________________________________
 
internal class RssItem
{
private string title;
private string href;
private string body;
private string tags;
private DateTime pubDate;
private string blogTitle;
private string blogLink;

public string Href
{
get { return href; }
}

public string Title
{
get { return title; }
}

internal RssItem()
{
title = "No Data Available At This Time.";
href = "~";
}

public string Body
{
get { return body; }
set { body = value; }
}

public string Tags
{
get { return tags; }
set { tags = value; }
}

public DateTime PubDate
{
get { return pubDate; }
set { pubDate = value; }
}

public string BlogTitle
{
get { return blogTitle; }
set { blogTitle = value; }
}

public string BlogLink
{
get { return blogLink; }
set { blogLink = value; }
}

internal RssItem(XmlNode xNode, string sBlogTitle, string sBlogLink)
{
title = xNode.SelectSingleNode("./title").InnerText;
href = xNode.SelectSingleNode("./link").InnerText;
body = FixDesc(xNode.SelectSingleNode("./description").InnerText, href);
pubDate = Convert.ToDateTime(xNode.SelectSingleNode("./pubDate").InnerText);

XmlNodeList nodeList = xNode.SelectNodes("./category");
foreach (XmlNode node in nodeList)
{
tags = tags + " " + node.InnerText;
}

BlogTitle = sBlogTitle;
blogLink = sBlogLink;
}

internal RssItem(XmlNode xNode, bool isAtom, string hrefUrl, string sBlogTitle, string sBlogLink)
{
if (xNode["title"] != null)
title = xNode["title"].InnerText;

if(!string.IsNullOrEmpty(hrefUrl))
href = hrefUrl;
else
{
if (xNode["link"] != null)
{
href = xNode["link"].Attributes["href"].Value.ToString();
}
}

if (xNode["content"] != null)
body = FixDesc(xNode["content"].InnerText, href);

if (xNode["published"] != null)
pubDate = Convert.ToDateTime(xNode["published"].InnerText);

if (xNode["category"] != null)
{
tags = xNode["category"].Attributes["term"].Value.ToString();
}

BlogTitle = sBlogTitle;
BlogLink = sBlogLink;
}

public string FixDesc(object desc, object link)
{
if (link == null desc == null) return String.Empty;

string description = desc.ToString();
Regex reg = new Regex("<.*?>", RegexOptions.Compiled);
string stripDesc = reg.Replace(description, String.Empty);

if (stripDesc.Length > 250)
{
int startPos = 250;
char[] chars = stripDesc.ToCharArray();
char c = chars[startPos];
while (!Char.IsWhiteSpace(c) && startPos < chars.Length)
{
startPos++;
c = chars[startPos];
}
stripDesc = new String(chars, 0, startPos) + "<br><a href=" + link.ToString() + " target='_blank'>More...</a>";

}
return stripDesc;
}
}

Tuesday, May 26, 2009

Differences between Rss and Atom

Here are some of the important differences between RSS and Atom XML structure.
This would help you while programatically reading the RSS / Atom of a blog.

RSS Atom Remarks
rss - check for this to differentiate between RSS/Atom
channel feed  
title title  
link link if you are trying to read the link… check the rel attribute of the link value to alternate and corresponding href attribute value. This is very important.
description subtitle content  value to be read instead.
language - Atom uses standard xml:lang attribute
copyright rights  
webMaster -  
managingEditor author or contributor  
pubDate published (in entry) Atom has no feed-level equivalent
lastBuildDate (in channel) updated RSS has no item-level equivalent
category category Read term attribute value.
generator generator  
docs -  
cloud -  
ttl - <ttl> is problematic, prefer HTTP 1.1 cache control
image logo Atom recommends 2:1 aspect ratio
- icon As in favicon.ico
rating -  
textInput -  
skipHours -  
skipDays -  
item entry  
author author  
- contributor  
description summary and/or content depending on whether full content is provided
comments -  
enclosure - rel="enclosure" on <link> in Atom
guid id  
source - rel="via" on <link> in Atom
- source Container for feed-level metadata to support aggregation

Thursday, May 21, 2009

Unable to create list (custom or from template)

Yesterday one of my friends called up and he was getting the below issue and was unable to create a new custom list or a list from a list template.

Object reference not set to an instance of an object. at ASP._layouts_new_aspx.OnLoad(EventArgs e) in c:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\12\TEMPLATE\LAYOUTS\new.aspx:line 23

He was able to create it however on dev / test / stage boxes but not on production.
Guess what??? the only difference was, production is on https.

Fix: Create the list on extended web site (Intranet) instead of creating on the public facing domain on https.

New Look for SharePoint Home Page

SharePoint Team Blog announced the new look and feel using SilverLight. Looks pretty cool.

link is here.

Friday, May 15, 2009

Using AllowUnsafeUpdates

Syntax: bool SPSite.AllowUnsafeUpdates

Would essentially tell if you need to update on database when request is of type 'GET' - 'WITHOUT SECURITY' Validation. Well first of all why do you want to do it?

Usage:

web.AllowUnsafeUpdates = true;

Best Practices:

1. DONT USE IT - If you use it, you are exposing yourself to the Cross-Site Scripting.

2. If the request is 'POST' you can happily use SPUtility.ValidateFormDigest() to execute your needs.

3. By default the value is set to 'FALSE' for all Request types 'GET'. Meaning, if some one is trying to update any list - unless and until you specify the property value to 'TRUE', SharePoint will not allow one to update the item.

So, you have to set it to 'TRUE' and then after your meet your requirement... set it to 'FALSE'.

bool allowUpdates = web.AllowUnsafeUpdates;
web.AllowUnsafeUpdates = true;
// WHAT I WANT TO DO?
web.AllowUnsafeUpdates = allowUpdates;

Disadvantage(s) of RunWithElevatedPrivileges

With Great Power Comes Great Responsibility!

Which means > More Security and then finally the chances of getting breached are? Read on...

SPSecurity.RunWithElevatedPrivileges - A very powerful delegate method to get your self a magic wand with which you can 'almost' get to everything you want.

When you run the context under RunWithElevatedPrivileges - function allows access to secured SharePoint objects from the object model by changing the WSS user account context to SHAREPOINT\System. The current windows user context now changes to the current application pool user, configured in IIS. In typical SharePoint farm installations, the application pool user is an AD user with restricted permissions and limited access to external resources, although typically this user has more permissions than the local IUSR_MACHINENAME user.

and now 'YOU' become 'System User' and have access to 'EVERYTHING' - a security hole.

Apart from this, you got to code for this delegate my dear.

Use your better judgement.

Thursday, May 14, 2009

Restricting Users to see other's information

Scenario:

Any user (or role) with Read permissions can view other users details. Well, many organizations and their users need to protect their own identities and details and this is quite common.

Now, the requirements can varify. Some organizations can block every one and their own (User Information List) and that way no one can view their own details. To acheive this; please view the blog post here.

You can come up with the idea saying that why cant we alter the layout pages and security trim them. Well, 2 things to keep in mind.
1. What if you dont have access to layouts page.
2. When new service pack arrives, it would overwrite the layout pages and your changes are gone. Alternatively you can maintain the copies of the layout pages you modify but then replace them back etc etc... a big maintanance nightmare.

So, recently we had a similar situation... our hands are more tied up. The Site is hosted on a hosting server where we had no control except modifying the UI using SPD 2007 (as point 1 above). And the users need to see their own details but not others and this was mandate.

One of the solutions (I dont claim its very good but a temporary hack) is here below.

Step 1: As an Admin go to _layouts/people.aspx
Step 2: Click on Settings > List Settings
Step 3: Click on Default view (at the end of the settings)
Step 4: Go to Filter Section
Step 5: Filter column by ID 'is equal to' 0 (ZERO)
Step 6: Click OK

Repeat this for 'List View' also.

This would actually not display anything.

Now, go ahead and create another view but this time 'Personal View' instead of 'Public View' which would be available only to the person who created it.

Hope this helps for you.

Wednesday, May 13, 2009

WSS 3.0 Master Page Quick Reference

My friend shared this with me and I feel we all can take advantage of this quick reference image to understand better and easy.



Tuesday, May 12, 2009

Programmatically Upload documents to SharePoint Document Library

Scenario: Upload a document (any type) to SharePoint Document Library programmatically.

How? : Use the below code.

Parameters:
1. docName: Name of the document with which you want to upload to the library
2. content: byte[] content of the document you want to upload
3. siteName: Site where you want to upload the document
4. docLibName: Document Library Name to which you want to upload the document


///
///
///

/// Name of the document
/// byte format of the document
/// site name
/// sharepoint document library name
private void UploadDocumentToSharePointLibrary(string docName, byte[] content, string siteName, string docLibName)
{
using (SPSite site = new SPSite(siteName))
{
using (SPWeb web = site.RootWeb)
{
SPFolder docFolder = web.Folders[docLibName];
SPFile file = docFolder.Files.Add(docFolder.Url + "/" + docName, content, true);

file.Update();
docFolder.Update();
}
}

}

Customizing Search Box in SharePoint

Scenario:

Customize search box control on your site.

Implementation:

Step 1:
Add the below lines of code to the register control tag section

<%@ Register Tagprefix="SPSWC" Namespace="Microsoft.SharePoint.Portal.WebControls" Assembly="Microsoft.SharePoint.Portal, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>

Step 2:
Search box control is found beteen the contentplaceholder

<asp:ContentPlaceHolder id="PlaceHolderSearchArea" runat="server">

and would be

<SharePoint:DelegateControl runat="server" ControlId="SmallSearchInputBox"/>

replace the above with the below code and add your fav images around to see a custom search box on your site.

<SPSWC:SearchBoxEx id="SearchButton" RegisterStyles="false" TextBeforeTextBox="" TextBoxWidth="88" GoImageUrl="/_layouts/images/GOSEARCH.GIF" GoImageActiveUrl="/_layouts/images/GOSEARCH.GIF" GoImageUrlRTL="" GoImageActiveUrlRTL="" UseSiteDefaults="true" DropDownMode="HideScopeDD" SuppressWebPartChrome="true" runat="server" WebPart="true" __WebPartId="{0043945F-2D2B-4A02-8510-CED13B6F04DF}"/>

the properties of this control are self explainatory and use them at your requirement.

Saturday, May 9, 2009

SharePoint Identity

Voila! This would be some thing I would have hard time to make one understand. This topic is simple until one keeps it flat, else a complete confusing serious session.

This post would be my attempt to make it very easy for beginners to understand it very easily to basic of Identity.

Well, lets understand the simple terms.

1. Authentication
a. FBA
b. Windows

2. Windows Account
a. IUSR_MachineName
b. App Pool User
c. Windows User

3. WSS Account
a. FBA User
b. Windows User
c. SHAREPOINT \ System

Now, I hope the following lines are not new for you...
<configuration>
<system.web>
<identity impersonate="true"/>
</system.web>
</configuration>

which means ASP.NET runtime impersonates the Windows Account passed by IIS. SharePoint keeps track of both Windows Account as well as WSS account. It uses the WSS Account to grant access to secure SPObjects (name it). However ASP.NET which is the base, impersonates the Windows Account when running Sharepoint Application and decides if the resources (webparts, custom etc) can access other resources (files, SQLServer etc).

During Windows Authentication, when user passes right credentials - IIS passes the windows user token to SharePoint. And SharePoint uses 'this context' and executes under this user context. Meaning at this point both WSS Account and Windows Account use same user.

On the other hand FBA is managed by ASP.NET rather than IIS. By default IIS passes the standard IUSER_MACHINENAME local user account token to ASP.NET. ASP.NET is configured to authenticate using forms by the following XML in the web.config file:

<configuration>
<system.web>
<authentication mode="Forms"/>
</system.web>
</configuration>

On successful authentication, SharePoint runs under the IUSER_MACHINENAME user context. The WSS account is depicted by the forms authentication identity, which is dependent on the membership provider configured in ASP.NET.

Now, when you run the context under RunWithElevatedPrivileges - function allows access to secured SharePoint objects from the object model by changing the WSS user account context to SHAREPOINT\System. The current windows user context now changes to the current application pool user, configured in IIS. In typical SharePoint farm installations, the application pool user is an AD user with restricted permissions and limited access to external resources, although typically this user has more permissions than the local IUSR_MACHINENAME user.

One problem with RunWithElevatedPrivileges is that, you now become System User and have access to 'EVERYTHING' - a security hole. So use caution while using it.

Friday, May 8, 2009

PDF Integration in SharePoint

1. Open DOCICON.XML file under C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\12\TEMPLATE\XML\ folder.

2. Add entry to the file as mentioned below (on all WFE's and Index servers)

<Mapping Key="pdf" Value="icpdf.gif" EditText="Adobe Acrobat" OpenControl="SharePoint.OpenDocuments" />

Note: EditText setting above will not work with Adobe Reader, it need to have professional version.

3. Get a 16x16 size pdf icon file from adobe (should be available on their site of just google it) and paste it to the below folder:

C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\12\TEMPLATE\IMAGES\

Make sure the name of the icon is 'icpdf.gif' or if you have it as xyz.gif then change the Value in above mapping tag.

4. IISRESET

Thats it! Simple isn't it?

Rounded Corners with CSS

Alright, here we go. Couple of ways you can achieve this. But before that I have to give the credit to many of those who made it possible for the second method mentioned below so that I dont reinvent the wheel.
___________________________________________
FUTURE: CSS3:

An exciting wave is going to come to eliminate the present and past. CSS3 in beta stage is going to have a new class border-radius. Isnt it awesome?

Syntax: border-radius: <len><len>
the are the lengiths left->Right and right->left.

for individual corners:
border-top-right-radius
border-bottom-right-radius
border-bottom-left-radius
border-top-left-radius

Unfortunatly since it is in beta phase we cannot use it. however, mozilla has a work around.

use the below and you will see it flying

blockquote{
-moz-border-radius: 2em;
border-radius: 2em;
}

___________________________________________
PAST AND PRESENT
___________________________________________
Method I. (Globally followed) : WITH IMAGES
Create 4 curved images (for 4 corners of table / cell / div) and use the below CSS format code and use the classes to set it to your table / cell / div.

CSS:

.topright {background: url(top_right.gif) 100% 0 no-repeat; padding:10px;}
.bottomright {background: url(bottom_right.gif) 100% 100% no-repeat;}
.topleft {background: url(top_left.gif) 0 0 no-repeat;}
.bottomleft {background: url(bottom_left.gif) 0 100% no-repeat;}

and in your page:

<div class="bottomright">
<div class="topleft">
<div class="bottomleft">
<div class="topright">
// YOUR CODE GOES HERE
</div>
</div>
</div>
</div>

________________________________________________
Method II. (Browser dependancy) : WITHOUT IMAGES

CSS:

div.rounded {
width: 9em;
background-color: #E6E6E6;
margin: 3px;
}
div.top-left-corner, div.bottom-left-corner,
div.top-right-corner, div.bottom-right-corner
{position:absolute; width:20px; height:20px;
background-color:#FFF; overflow:hidden;}
div.top-left-inside, div.bottom-left-inside,
div.top-right-inside, div.bottom-right-inside
{position:relative; font-size:150px; font-family:arial;
color:#E6E6E6; line-height: 40px;}
div.top-left-corner { top:0px; left:0px; }
div.bottom-left-corner {bottom:0px; left:0px;}
div.top-right-corner {top:0px; right:0px;}
div.bottom-right-corner {bottom: 0px; right:0px;}
div.top-left-inside {left:-8px;}
div.bottom-left-inside {left:-8px; top:-17px;}
div.top-right-inside {left:-25px;}
div.bottom-right-inside {left:-25px; top:-17px;}
div.box-contents {
position: relative; padding: 8px; color:#000;
}

<div class="rounded">
<div class="top-left-corner">
<div class="top-left-inside">
</div>
</div>
<div class="bottom-left-corner">
<div class="bottom-left-inside">
</div>
</div>
<div class="top-right-corner">
<div class="top-right-inside">
</div>
</div>
<div class="bottom-right-corner">
<div class="bottom-right-inside">
</div>
</div>
<div class="box-contents">
// YOUR CONTENT GOES HERE
</div>
</div>