Wednesday, November 26, 2008

Adding content type programatically

Scenario:
You want to add Content Type programatically

Solution:
SharePoint Object Model

Code:

using (SPSite site = new SPSite("http://localhost")) { 

using (SPWeb web = site.OpenWeb()) {

SPContentType baseType = web.AvailableContentTypes["Document"];

SPContentType proposal = new SPContentType( baseType, web.ContentTypes, "Project Proposal");

proposal.FieldLinks.Add(new SPFieldLink(web.AvailableFields["Author"]));

web.ContentTypes.Add(proposal);

}
}
Article:

Web Config Modification Feature

Scenario:
You want to automate the modification to Web.config.

Solution:
Intelligent use of Feature receiver can help.

Code:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;

namespace MyClient
{
class WebConfigModifierFeature : SPFeatureReceiver
{
public override void FeatureInstalled(SPFeatureReceiverProperties properties) { }
public override void FeatureUninstalling(SPFeatureReceiverProperties properties) { }

public override void FeatureActivated(SPFeatureReceiverProperties properties)
{
SPWebApplication application = (SPWebApplication)properties.Feature.Parent;

foreach (ModificationEntry entry in this.SectionEntries)
{
application.WebConfigModifications.Add(this.CreateModification(entry.Name, entry.XPath, entry.Value, SPWebConfigModification.SPWebConfigModificationType.EnsureSection ));
}
foreach (ModificationEntry entry2 in this.ChildNodeEntries)
{
application.WebConfigModifications.Add(this.CreateModification(entry2.Name, entry2.XPath, entry2.Value, SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode));
}
foreach (ModificationEntry entry3 in this.AttributeEntries)
{
application.WebConfigModifications.Add(this.CreateModification(entry3.Name, entry3.XPath, entry3.Value, SPWebConfigModification.SPWebConfigModificationType.EnsureAttribute));
}
application.Farm.Services.GetValue<SPWebService>().ApplyWebConfigModifications();
application.Update();
}

public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
{
SPWebApplication application = (SPWebApplication)properties.Feature.Parent;

foreach (ModificationEntry entry in this.AttributeEntries)
{
application.WebConfigModifications.Remove(this.CreateModification(entry.Name, entry.XPath, entry.Value, SPWebConfigModification.SPWebConfigModificationType.EnsureAttribute ));
}
foreach (ModificationEntry entry2 in this.ChildNodeEntries)
{
application.WebConfigModifications.Remove(this.CreateModification(entry2.Name, entry2.XPath, entry2.Value, SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode));
}
application.Farm.Services.GetValue<SPWebService>().ApplyWebConfigModifications();
application.Update();

}

private struct ModificationEntry
{
public string Name;
public string XPath;
public string Value;

// parameterized contructor
public ModificationEntry( string Name, string XPath, string Value )
{
// intialize structure instances
this.Name = Name;
this.XPath = XPath;
this.Value = Value;
}
}

private ModificationEntry[] AttributeEntries = new ModificationEntry[] {
new ModificationEntry("defaultProvider", "configuration/system.web/membership", "MyMembershipProvider"),
new ModificationEntry("userIsOnlineTimeWindow", "configuration/system.web/membership", "15") };
private ModificationEntry[] ChildNodeEntries = new ModificationEntry[] {
new ModificationEntry("add[@name='MyConnectionString']", "configuration/connectionStrings", "<add name=\"MyConnectionString\" connectionString=\"Data Source=myserver;Initial Catalog=mydb;User Id=USER1;Password= pass@word!;\" providerName=\"System.Data.SqlClient\" />"),
new ModificationEntry("add[@name='MyMembershipProvider']", "configuration/system.web/membership/providers", "<add name=\"MyMembershipProvider\" type=\"GlobalConfigFeature.MyMembershipProvider, GlobalConfigFeature, Version=1.0.0.0, Culture=neutral, PublicKeyToken=0c64981f6ea780b0\" applicationName=\"/\" passwordFormat=\"Clear\" description=\"Authenticates users against CRM\" connectionstring=\"CRM4M\"/>"),
new ModificationEntry("add[@name='MyHttpHandler']", "configuration/system.web/httpModules", "<add name=\"MyHttpHandler\" type=\"GlobalConfigFeature.MyHttpHandler,GlobalConfigFeature, Version=1.0.0.0, Culture=neutral, PublicKeyToken=0c64981f6ea780b0\" />"),
new ModificationEntry("add[@key='MyMembershipProvider']", "configuration/SharePoint/PeoplePickerWildcards", "<add key=\"MyMembershipProvider\" value=\"%\" />"),
new ModificationEntry("add[@key='UseCustomProfileDashboard']", "configuration/appSettings", "<add key=\"UseCustomProfileDashboard\" value=\"false\" />") };
private ModificationEntry[] SectionEntries = new ModificationEntry[] {
new ModificationEntry("appSettings", "configuration", "appSettings"),
new ModificationEntry("connectionStrings", "configuration", "connectionStrings"),
new ModificationEntry("membership", "configuration/system.web", "membership"),
new ModificationEntry("providers", "configuration/system.web/membership", "providers") };

public SPWebConfigModification CreateModification(string Name, string XPath, string Value, SPWebConfigModification.SPWebConfigModificationType Type)
{
SPWebConfigModification modification = new SPWebConfigModification(Name, XPath);
modification.Owner ="MyClient";
modification.Sequence= 0;
modification.Type=Type;
modification.Value= Value;
return modification;
}
}
}
Article:
Reza , Ted Pattison , Mark

Follow up:
While discussing the manageability of the Web.Config changes ( specially AppSettings ) , as they were growing fast. I wrote a modified version of the same feature here

Where is GACUtil ?

Scenario:
You want to automate few things in your developemt environment and one common thing you want to do is to push binaries to GAC easily.

Solution:
You can use GACUtil.exe , but where is it.

Look at following places
1. C:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\Bin\
2. C:\Program Files\Microsoft Visual Studio 9.0\SDK\v3.5\Bin\
3. C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin
4. C:\Windows\Microsoft.NET\Framework\v1.1.4322
5. More google

Code(PushToGAc.bat):

@SET GACUTIL="C:\Windows\Microsoft.NET\Framework\v1.1.4322\gacutil.exe"

%GACUTIL% /u "MyDllName, Version=1.0.0.0, Culture=neutral, PublicKeyToken=53f6ae95f6ddsa1"

%GACUTIL% -I bin\debug\MyDLLName.dll

cscript c:\windows\system32\iisapp.vbs /a "[App_Pool_Name]" /r

Article:

Saturday, November 22, 2008

Getting Current User in Infopath UI

Scenario:
You want to know the currently logged in user name to do some formatting.

Solution:
You can use inbuild function to get the information.

To get the current use name:

username()

These functions are only available in InfoPath 2007.

Getting Current user role in Infopath code-behind

Scenario:
Infopath 2003/2007 has .net language support. In your code you want to do execute some logic depending upon the Logged in User Role.

Solution:
You can use the in-build method to get the role.

Code:


bool userRole = thisApplication.User.IsUserMemberOf(@"Domain\Group");

if (userRole)
{
//do something cool here
}
Notes:
However, there is a catch here. This works only if the user who is accessing the form and the group specified in the user roles are of the same domain.

So, the following are the valid and invalid combinations

Invalid Combination:

User: AMERICA\Employees
Group: ASIA\SecurityGroup

Valid Combination:

User: AMERICA\Employees
Group: AMERICA\Administrators

Thursday, November 20, 2008

The security validation for this page is invalid

Scenario:
You have create a new ASPX page and trying to run it under SharePoint context. If the page Postback you get the following error.
The security validation for this page is invalid.

Reason:
SharePoint uses Form validation digest to stop attacks.

Solution:
1. You can disable the security
http://www.sharepointblogs.com/nicksevens/archive/2007/11/23/edit-sharepoint-security-in-c-quot-the-security-validation-for-this-page-is-invalid-quot.aspx

2. Use the SharePoint master page to get the correct 'form' for your page. What I mean by that is , there is a sharepoint control which takes care of security validation. All the sharepoint master pages have it. So if you use sharepoint master page this is taken care.( BEST )

3. Add the form details into the page manually.
http://epham.wordpress.com/2007/01/22/how-to-fix-security-validation-errors-in-sharepoint-aspnet-page/

4. Allow unsafe update ( if updating sharepoint objects )
http://blogs.msdn.com/sridhara/archive/2008/06/21/the-security-validation-for-this-page-is-invalid-error-when-updating-objects-through-sharepoint-object-model.aspx

Friday, November 14, 2008

Wishlist SharePoint Office 14

Should have
01. Preview for blog and list item editing...without sending email alerts to subscribers.

02. More Custom Action Menu's with security trimming.

03. Hiding Left Navigation , Top Navigation options.

04. Rule based option for 'Alert Me' to be able to recieve alert.

05. Alert Template selection option under 'List Settings'.

06. Easy way to make changed to 'Web.Config'. Some sort of merge mechanism.

07. Custom Folder structure support in FEATURES folder.

08. Easier way to add new file type without editing DOCICON.xml

09. Easier way to add new Alert templates without editing AlertTemplates.xml

10. Custom Folder structure support in Solution Management.

11. Ability to collect input while Activating Feature, kinda like in workflow with initiation data.

12. New Field types ( With privacy options ) http://www.infoq.com/articles/Dressel-Gogolowicz-wss-security

13. Way to execute Timer Job every few hours ( every 4 hrs )

14. Feature Stapling option of existing sites ( may be by specifying an attribute )

15. Select All / Remove All for the lookup field control

16. Workflow for site collection / site level , currently for list/library only

Missing

1. Ability to create publishing / webpart pages - within subfolders.

Some Ideas
1. User personalizable themes ( Delegate Control )

2. Meta Data Injector ( Delegate Control )

3. Request Access List with Accept Reject Option

Friday, November 7, 2008

Hiding/Showing items depending upon list meta-data

Scenario:
You want to toggle visibility of the list items depending upon particular audience.
i.e Group A should be able to see some documents/items if one of the meta-data field says A.

Solution:
List Audience Targeting

Steps:
1. Create various different Audience in Share Service Provider with rules using MetaData.
2. Go to the List > 'Advanced Settings'
3. Click on 'Audience Targeting'
4. Select 'Enable Audience Targeting'
5. You will get an extra column for each item 'Targeted Audience'
6. Specify the created audience and this will toggle the document/item visibility.

Note:
Audience is not Security as user can still reach to the item if he know the Url.

Article:
Code Guru

Wednesday, November 5, 2008

What are Control Adapters ?

Control adapters are simply a way of providing different renderings for controls without actually modifying the controls themselves. Because control adapters are designed to provide alternate renderings for different clients, you specify control adapter mappings in a .browser file, which is where associations between User Agent strings and browser capabilities are defined.

The control adapter class itself must inherit from the System.Web.UI.Adapters.ControlAdapter, which is an abstract base class that looks much like the Control base class, with events for Init, Load, PreRender, and Unload, as well as a virtual Render method.

Resources

ASP.Net
http://weblogs.asp.net/scottgu/pages/ASP.NET-2.0-Tips_2C00_-Tricks_2C00_-Recipes-and-Gotchas.aspx

http://www.asp.net

SilverLight
http://weblogs.asp.net/scottgu/pages/silverlight-posts.aspx

Silverlight Official Home

Power Shell

Form Based Authentication for SharePoint

Scenario:
You want to configure Form Based Authentication ( FBA ) for the a group of users.

Solution:
Again , SharePoint is nothing but ASP.Net application, so the process is almost the same for SharePoint. Also SharePoint comes with its own Login.aspx page Out-Of-Box , so no need to design one.

Article:
http://msdn.microsoft.com/en-us/library/bb975136.aspx ( 3 Part series )

http://www.simple-talk.com/dotnet/windows-forms/configuring-forms-authentication-in-sharepoint-2007/

http://www.codeplex.com/fba

http://blogs.msdn.com/harsh/archive/2007/01/10/forms-based-authentication-in-moss.aspx


Products:

Changing port for Central Administration Web Application

Scenario:
You want to change the port number for the Web Application hosting Central Administration

Solution:
Use STSADM utility.

Code:

Stsadm –o setadminport –port 5555
Article:
http://technet.microsoft.com/en-us/library/cc262249.aspx

Tuesday, November 4, 2008

Backup site collection using Powershell

Scenario:
You want to backup site collection.

Solution:
You can use Powershell script as an option

Code:

###########################################################
# Script to add function to properly backup site collections
#
# SYNTAX:
# Backup-SPSite
# -url <Site Collection URL>
# -path <path to backup file>
# -lock <"noadditions", "noaccess", "readonly"> #state for backup
# -AdditionalCommands [additional commands for Backup]
# Restore-SPSite
# -url <site collection restore url>
# -path <path to backup file>
# -force
#
# EXAMPLE:
# backup-spsite -url "http://localhost" -path "C:\zbackuptest.bak" -AdditionalCommands "-overwrite"
###########################################################

function global:Backup-SPSite($url,$path,$lock="noaccess",$additionalcommands){
$stsadm = "$env:programfiles\Common Files\Microsoft Shared\Web Server Extensions\12\BIN\STSADM.EXE"

#Check Required Vars
If($url -eq "" -or $url -eq $null ){ Write-Host -ForegroundColor "Red" "URL is required"; return; }
If(!($lock -like "none" -or $lock -like "noadditions" -or $lock -like "noaccess" -or $lock -like "readonly" )){ Write-Host -ForegroundColor "Red" "Lock must be 'none', 'readonly', 'noaccess', or 'noadditions'"; return; }
#Setup Variable Defaults

#LOCK SITE
Write-Progress -Activity "Backup SPSite" -PercentComplete 25 -Status "Locking Site"
$oldlockstate = [xml](&stsadm -o getsitelock -url $url)
$void = &stsadm -o setsitelock -url $url -lock $lock

#BACKUP
Write-Progress -Activity "Backup SPSite" -PercentComplete 50 -Status "Backing up Site ($url)"
$sTemp = &stsadm -o Backup -url $url -filename $path $AdditionalCommands
if(!($sTemp -like "*Operation completed successfully*")){ Write-Host -ForegroundColor "red" -BackgroundColor "white" "Backup of site '$url' Failed! `n $stemp"}

#RESET LOCK STATE
Write-Progress -Activity "Backup SPSite" -PercentComplete 75 -Status "Resetting Site Lock"
$void = &stsadm -o setsitelock -url $url -lock ($oldlockstate.SiteLock.Lock.ToString())
Write-Progress -Activity "Backup SPSite" -PercentComplete 100 -Status "Complete"
}
Article:

SharePoint Web Services and Java

Scenario:
You want to talk to MOSS using Java.. No problem...

Solution:
SharePoint Web Services

Article:
http://www.infoq.com/articles/swanson-moss-web-services

Sunday, November 2, 2008

Adding a new metadata property to search

Scenario:
You want to add new Managed Properties to the SharePoint Search results.

Solution:
Shared Service Administration Web Application provide you the options to add new Managed Properties

Steps:
1. Navigate to Central Administrative Web Application
2. Click on 'SharedServices1' link from the left navigation
3. Click on 'Search Settings'
4. Click on 'Metadata property mappings'
5. Click on 'New Managed Property'
6. Type a Name for the property and select the Type
7. Click on the 'Add Mapping' button from the bottom section
8. Search for the property or the column name , you want to map.
Note: If you are not able to find the column name or property you want to map, full crawl might be required for SharePoint Search to pickup the proprty.
9. Click 'OK' Button to add it
10. Run a full crawl for the Content Source containing the column infomation

Article:
http://sharepointmagazine.net/technical/customisation/customizing-search-series-creating-new-managed-properties-from-bdc-crawled-content

Add FBA users to sharepoint programmatically

Scenario:
You want to add FBA users to one of the SharePoint Group

Solution:
1) Create FBA Membership User
2) Create SharePoint User
3) Get your site instance
4) Add SharePoint User to a Desired group

Code:


MembershipUser membershipUser = Membership.CreateUser(login, password, email);

SPWeb spWeb = SPControl.GetContextWeb(HttpContext.Current);

SPUser spUser = spWeb.EnsureUser(login);
SPGroup spGroup = spWeb.SiteGroups["VISITORS"];
spGroup.AddUser(spUser);

Possible Errors:
[SPException: The user does not exist or is not unique.]
or 
When You try to put this new user into a sp group, the web is redirected to the login page


Article:
http://social.msdn.microsoft.com/forums/en-US/sharepointdevelopment/thread/db46ab8f-9594-4878-9bab-a18fe3fba959/

List Template Id's and Base Type

ListTemplateIds for various list types is as following:


100 Generic list
101 Document library
102 Survey
103 Links list
104 Announcements list
105 Contacts list
106 Events list
107 Tasks list
108 Discussion board
109 Picture library
110 Data sources
111 Site template gallery
112 User Information list
113 Web Part gallery
114 List template gallery
115 XML Form library
116 Master pages gallery
117 No-Code Workflows
118 Custom Workflow Process
119 Wiki Page library
120 Custom grid for a list
130 Data Connection library
140 Workflow History
150 Gantt Tasks list
200 Meeting Series list
201 Meeting Agenda list
202 Meeting Attendees list
204 Meeting Decisions list
207 Meeting Objectives list
210 Meeting text box
211 Meeting Things To Bring list
212 Meeting Workspace Pages list
301 Blog Posts list
302 Blog Comments list
303 Blog Categories list
1100 Issue tracking
1200 Administrator tasks list
Base Type values is as following:

0 Lists
1 Document libraries
3 Discussion boards. Does not support custom view styles.
4 Surveys. Does not support custom views or view styles.

Batch update list items using CAML

Scenario:
You want to batch update small amount of items in a list ( usually less then 100 in one time items ) 

Solution:
You can use CAML query to make the BULK update. Performace will degrade as the number of items to be updated increases. This example updates 100 items each time.

Code:

StringBuilder methodBuilder = new StringBuilder();
string batch = string.Empty;
DateTime currentDate = DateTime.Now;
string formattedDate = SPUtility.CreateISO8601DateTimeFromSystemDateTime(currentDate);

string batchFormat = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
"<ows:Batch OnError=\"Return\">{0}</ows:Batch>";

string methodFormat = "<Method ID=\"{0}\">" +
"<SetList>{1}</SetList>" +
"<SetVar Name=\"Cmd\">Save</SetVar>" +
"<SetVar Name=\"ID\">{2}</SetVar>" +
"<SetVar Name=\"urn:schemas-microsoft-com:office:office#Status\">{3}</SetVar>" +
"<SetVar Name=\"urn:schemas-microsoft-com:office:office#Status_x0020_Date\">{4}</SetVar>" +
"</Method>";

using (SPSite site = new SPSite("http://localhost"))
{
using (SPWeb web = site.OpenWeb())
{

// Get the list containing the items to update.
SPList list = web.Lists["Shared Documents"];
string listGuid = list.ID.ToString();

// Query to get the unprocessed items.
SPQuery query = new SPQuery();
query.Query = "<Where><Neq><FieldRef Name='Status'/>
<Value Type='Choice'>Open</Value></Neq></Where>";
query.ViewAttributes = "Scope='Recursive'";
query.RowLimit = 100;

SPListItemCollection unprocessedItems = list.GetItems(query);

do
{
SPListItemCollection unprocessedItems = list.GetItems(query);

//Process all the returned items in this page
// Build the CAML update commands.
for (int i = 0; i < unprocessedItems.Count; i++)
{
int itemID = unprocessedItems[i].ID;
methodBuilder.AppendFormat(methodFormat, itemID, listGuid, itemID, "In-Progess", formattedDate);
}

// Put the pieces together.
batch = string.Format(batchFormat, methodBuilder.ToString());

// Process the batch of commands.
string batchReturn = web.ProcessBatchData(batch);

query.ListItemCollectionPosition = unprocessedItems.ListItemCollectionPosition;
} while (query.ListItemCollectionPosition != null);
}
}
}
Article:http://msdn.microsoft.com/en-us/library/cc404818.aspx