Tuesday, October 18, 2011

Get SPContext.Current.ListItem in SharePoint layouts page

I was developing a layouts page to view a list item for anonymous users with custom styles. So I was doing a little research on how to get the reference to the current list item (SPContext.Current.ListItem) so that the field values can be easily bound using SharePoint web controls itself.

It turns out to be, if a layouts page is being referenced relative to a proper web, and the List id and Item id are passed in as parameters, then I can get the SPContext.Current.ListItem referencing to the particular item being viewed and I can make use of the SharePoint Web Controls to display the field values.

http://localweb/{web url}/_layouts/ViewItem.aspx?List={list guid}&ID={itemid}

Example: http://localweb/home/_layouts/ViewItem.aspx?List={E2E0527C-EFB1-42D4-8FFE-20A6AC364845}&ID=1


In the ViewItem.aspx, I can make use of SharePoint web controls in the layouts page to display the field values as:

<SharePoint:FieldValue FieldName="Title" runat="server" />
 
Hope this helps some one else.

Thanks
Happy Coding
Senthil S

Monday, October 17, 2011

Custom Alerts in Sharepoint 2010



Alerts are automated emails generated by Sharepoint when something changes (a list item for example) and if any user has created an alert for that particular change in the list item.

In some scenarios, we may want to customize the alert email generated by the Sharepoint 2010. This can be done in two ways

1. Altering the OOTB alert template xml to use whatever the text you would like to have in the alert email
2. Adding a custom alert handler in the dll deployed to GAC and alter the alert template xml to make use of that

I personally prefer the second method since we (programmers) have more control over the email subject and body and I find it little complex to achieve my particular situation (altering the default url to link the edited/changed item).

Option 1:
To briefly describe the first option, the OOTB alert template files need to be modified. The template file can be found under {root}\TEMPLATE\XML\alerttemplate.xml. In this file you can find AlertTemplate for different list types. For my purpose I had to modify for the discussion lists (Name="SPAlertTemplateType.DiscussionBoard). Inside an AlertTemplate XML item, you will find two elements "Digest" and "Immediate" one for each type of alert. To retrieve additional fields when generating the alert message, modify "ImmediateNotificationExcludedFields" and "DigestNotificationExcludedFields" respectively and make use of those fields in the xml itself.

With that said, I have done only a basic research on the above method.

Option 2:
To have the modification done using the Second option, the above template file needs to be modified to tell the SharePoint to use a custom handler when generating alert emails.

Please COPY the original alerttemplate.xml file and work on the copy. DO NOT CHANGE THE ORIGINAL.
In the file add the reference to the custom handler that you created and deployed to GAC (I'll explain how to create the alert handler later)

Find the "Properties" node under the AlertTemplateType and add the reference like this

After updating, a powershell script needs to be run to update SharePoint to make use of the handler. Like this below.



After doing the update statement, the SharePoint services need to be restarted. To restart them, you can use the below PowerShell script
 

Thats it. After this the custom handler must be called whenever an aler email is generated based on all discussion boards

Custom Handler Creation:
Now. How to create the custom alert handler for SharePoint 2010. Below is a sample code for a simple alert handler


Hope this helps some one else.

Thanks
Senthil S

Friday, October 14, 2011

Provisioning custom list when creating a site through onet.xml

Recently, I had a situation where I need to provision a custom list which has the list template defined in the project itself. We know how to provision an OOTB list using onet.xml as explained in this msdn document

http://msdn.microsoft.com/en-us/library/ms474369.aspx

But, I was facing an error when I was trying to provision a custom list using a custom list definition. I added a new list definition like below.

 In the onet.xml, I had to add the below statement to provision a list instance based on the above list template.


The FeatureId is the feature id attribute of the feature in which the ListTemplate is added.

Hope this helps someone else too.

Thanks
Senthil S

Tuesday, September 27, 2011

Adding a lookup field to a list programatically

Alright, I had a requirement where a lookup field needs to be added to list referencing another list's ID column. I managed to do this using the below code. You can understand without explaining all the inner details, I think.

//Adding a lookup column to link the item to the related item
var list = web.Lists["LookupListName"];
thisList.Fields.AddLookup("LookupFieldName", list.ID , web.ID, true);
SPFieldLookup lookupField = reportThisList.Fields.GetField("LookupFieldName" 
                                 as SPFieldLookup;
lookupField.LookupField = "ID";
//Adding indexing to enable "CACADE" delete of this list items
lookupField.Indexed = true;
//CASCADE - deletes all the related items in this list when an item is deleted.
lookupField.RelationshipDeleteBehavior = SPRelationshipDeleteBehavior.Cascade;
lookupField.Update(true);

After doing this above code, you will see a new column in the list (thisList). Here is a preview












If an item is deleted from the related list("LookupListName"), all the related items in thisList would get deleted automatically.

I know this might not give you a clear explanation. If you need more details, just add a comment, I will try to explain it in more detail.

Thanks
Senthil S

Adding list event receivers programatically

Recently, I was in a situation where event receivers needs to be attached to a SPList. Here is how it can be added dynamically using the api.



Like the above code, we can add the event receivers for any list event.

I have not tried the same for any other event receivers, but I am guessing it should be working the same way.

Thanks
Senthil S

Saturday, September 10, 2011

Check whether alerts are turned on for a Web Application

Even, if a user has an alert created for a list or list item or any other kind of alert, the alerts need to be turned on for the particular web application from the Central Admin.

How do we check whether it is turned on or not?

  • Go to Central Admin -> Application Management -> Manage Web Applications
  • Select the Web Application and select General Settings option from the tool bar
  • Make sure "Alerts on this server are "Tuned On"

Hope this helps someone

Senthil

Thursday, August 25, 2011

Allowing anonymous users access to SharePoint user's profile pictures

I was developing discussion groups using web parts where I needed to show the discussion posting authors' profile images with the posting detail.

First problem I faced was, how to get the profile image url of the user. I was able to find the details about the User Information List living in the RootSite of the site collection. I was able to get the related user info by getting the list item as below and get the "Picture" property value
and properly formatting it. 

userPictureUrl = SPContext.Current.Site.RootWeb.SiteUserInfoList.GetItemById(itemCreator.ID)["Picture"].ToString(); 
SPFieldUrlValue userProfileImage = new SPFieldUrlValue(userPictureUrl);
authorProfileImageUrl = (new Uri(userProfileImage.Url)).AbsolutePath;
 
But, then I faced the next issue of viewing user's profile image as an anonymous user. To achieve that I had to go through the below process of granting anonymous users access to List and libraries in the mys site site collection and granting "View Items" access to user profile pictures library.

STEP 1:
Go to http://<<MysiteSitecollection web url>>/_layouts/settings.aspx
Go to "Site Permissions" and click Anonymous Access from the ribbon
Select "Lists and libraries" and click "OK".



STEP 2:
Go to View All Site Content -> User Photos -> Settings (Picture Library Settings)
Go to "Permissions for this picture library"
Click "Stop Inheriting Permissions"
Click "Anonymous Access" from the ribbon
Check off "View Items" and click "OK"


After performing the above steps anonymous users were able to get access to profile pictures of other users.

Senthil S

Thursday, August 18, 2011

Security validation exception when updating list items

Recently, I faced an exception when trying to update an existing list item programatically. When trying to update the list item i.e., when trying to do SPListItem.Update(), I was getting the below exception message
           
              "Microsoft.SharePoint.SPException: The security validation for this page is invalid. Click Back in your Web browser, refresh the page, and try your operation again."

After some time, I found that I need to set the "AllowUnsafeUpdates" property of the parent web of the list item to true before doing an update.

               targetWeb.AllowUnsafeUpdates = true;
               listItem["Title"] = newTitle;
               listItem.Update();
               targetWeb.AllowUnsafeUpdates = false;

This should work if the current user has proper privileges, otherwise the above code needs to be ran under an impersonated context.

Probably, the same will happen when creating, deleting a list item too.  Happy coding ...


Senthil

Wednesday, June 29, 2011

Finding Page Layouts and Master Page usages


Recently, I messed up my page layout by manually editing the layout directly from the gallery. It started adding multiple web part instances all of a sudden when a page created with the page layout. So I decided to delete the layout and re-deploy the solution again.

I was getting the below error when I was trying to delete that particular page layout from my site collection's Master page and page layouts collection. (http://spsiteurl/_catalogs/masterpage/Forms/AllItems.aspx)

And I have deleted all the instances where ever the layout was being used. I was sure I was missing some place but how do I find that out??




After a long search I found a place where to get all the usages of page layouts. I went to  the Site Content and Structure by selecting "Manage Content and Structure" from the "Site Actions" menu. And navigated to the "Master Page Gallery" list in the root web.



We do have an option in the menu on the right side pane to show the related resources "Show Related Resources" to show/hide the related resources. Turning on this option and selecting the particular page layout or master page would show you the resources using the particular layout/master page.

A preview ...


Isn't this handy & cool??

Monday, June 13, 2011

Check-in & Check-out using ECMA script in SharePoint 2010

Recently, I had to enable editing just the content (not web part zones) of a publishing page by end users without the ribbon. I decided to make use of the ECMA script model to empower end users to update just the content of the page.

Provide buttons for different operations of a publishing page (edit, save and cancel) and handle the events in javascript coding and some jQuery.

I came across Sohel's blog with a pretty good description of how to make use of the ECMA script. It is basically, all the updates need to be set in its corresponding javascript objects and then "executeQueryAsync" must be called on the ClientContext object to save everything on to the server.

One porblem I faced was updating a particular field content in the current list item being edited. After doing some research on MSDN, I came across this function SP.File.listItemAllFields on MSDN (http://msdn.microsoft.com/en-us/library/ee557727.aspx) and started down that path.

I was able to check-out the current PublishingPage, update the corresponding list item and publish the page using current user's permissions.

function checkOut(){
        var ctx = SP.ClientContext.get_current();
        var page = ctx.get_web().getFileByServerRelativeUrl(window.location.pathname);
        page.checkOut();
        ctx.load(page);
        ctx.executeQueryAsync(Function.createDelegate(this, checkOut_Success),
                                            Function.createDelegate(this, checkOut_Fail));
}
function checkOut_Success(sender, args){
        //Do all sort of jquery to insert your own RTE control to edit the page contents
}
function checkOut_Fail(sender, args){
       //Do some error checking
}

function checkIn(){
         var ctx = SP.ClientContext.get_current();
        var web = ctx.get_web();
        var page = web.getFileByServerRelativeUrl(window.location.pathname);

        if (contentEditorNicInstance != null) {
            var listItem = page.get_listItemAllFields();
            listItem.set_item("PublishingPageContent", "{Updated content from the UI}");
            listItem.update();
        }
        page.checkIn();
        page.publish();
        ctx.executeQueryAsync(Function.createDelegate(this, checkIn_Success),
                                            Function.createDelegate(this, checkIn_Fail));
}
function checkIn_Success(sender, args){
       //This is to refresh the page after successful publishing with the new updated content.
      //If the page is not refreshed, the ECMA script will not support further check-in's and comes back with an error as "version conflict"
       window.location = window.location;
}
function checkIn_fail(sender, args){
      //Handle the error message
}

I think I am helping myself to remember this in future and also few others with their coding.

Senthil


Wednesday, May 25, 2011

Creating multi level discussion groups programmatically

Recently, I was required to create a multiple level discussion groups.

As we know, Sharepoint 2010 offers only one level of Discussion group (at least as far as I know) i.e., First level is Discussion Group and the inner level is Discussion Threads (individual posts).


What did I do, I create the discussion group programmatically and move the created group under an existing discussion group. This way, I was able to achieve multiple levels of discussion groups.

 var web = SPContext.Current.Web;    
 var discussionList = web.Lists[DISCUSSION_LIST_NAME];
 var discussionContentType = 
web.AvailableContentTypes[DISCUSSION_CONTENT_TYPE_NAME];
 
web.AllowUnsafeUpdates = true;
  
 var newDiscussionItem = SPUtility.CreateNewDiscussion(discussionList, title);
 newDiscussionItem["Title"] = title;
 newDiscussionItem["ContentTypeId"] = discussionContentType.Id;
 newDiscussionItem["ContentType"] = discussionContentType.Name;
newDiscussionItem.Update();
 
 //if the discussion group is a child discussion (Thread) 
 //then move the discussion group 
 //to a sub level (under its parent discussion group)
 if (parentDiscussionID != -1)
 {
    var parentDiscussionGroup = discussionList.GetItemById(parentDiscussionID);
    var destinationUrl = parentDiscussionGroup.Url + "/" 
+ newDiscussionItem.Folder.Name;
    newDiscussionItem.Folder.MoveTo(destinationUrl);
 }
 web.AllowUnsafeUpdates = false;
 
 
Using the above method of .Folder.MoveTo() any SPListItem can be moved to any destination. Hope this would help someone else.

Friday, May 6, 2011

Save a PublishingPage programmatically

We are trying to do edit and save page functionality for a publishing page programmatically. I was facing an issue where the page content is not getting updated when check-in the page programmatically. As we know the below code checks in and publishes any SharePoint item into the library.

SPContext.Current.ListItem.File.CheckIn("Page edited at: " + DateTime.Now,  
                                                SPCheckinType.MajorCheckIn);
SPContext.Current.ListItem.File.Publish("Published page at: " + DateTime.Now);

When I run the above code, the page gets checked in and gets published but the content is not getting updated in the page. To achieve that, I had to add the below code to save the contents of the page before check-in and publish the SharePoint item.

Microsoft.SharePoint.WebControls.SaveButton.SaveItem(SPContext.Current, 
                                         false"Saved at: " + DateTime.Now);

This one works fine for me. Hope this helps some one else too.

Monday, April 4, 2011

Creating a Taxonomy (Managed Metadata) field (SiteColumn) using definition xml

I was in a situation where I have to create a taxonomy bound site column for our SharePoint 2010 site. First I found it little difficult but SPCAMLEditor gave me a hand in figuring out the Taxonomy field structure in the SharePoint site. One Taxonomy field uses a set of two different fields to store the value.

When I need to create a SiteColumn named "TestColumn", a taxonomy column needs two different fields (TestColumn and TestColumn_0) for the field to work properly

TestColumn is of type "TaxonomyFieldType" and TestColumn_0 is of type "Note". The "TestColumn" references the TestColumn_0 in its field definition as a TextField.

I created the FieldDefinitions by copying the Schema xml to my project as a field definition xml file. When the field definition is deployed to a test server, the field is not saving any of the selected values. It allowed me to select the values but the values are not getting stored. After spending some time, I found that the Schema definition for the "TestColumn" references the ListId and WebId that it was created from in my local machine. Once I removed those references, it started working fine.



















Hope this is helping some one else.

Senthil Subramanian

Tuesday, March 29, 2011

Adding SPNavigationNode to current navigation programatically in SPWebEventReceiver

When I provision a site using custom site template we may want to customize the Left navigation bar. I wanted to clear out all the navigation and have My own custom static links in newly created site.

As we know we can change the navigation using UI by customizing navigation under Site Settings > Navigation > Navigation Editing and Sorting. But I am trying to do it through programatically and was able to clear out all the navigation. When I try to create a new heading and save to the site navigation, it was failing to save it.

So the trick is to get the Publishing web using PublishingWeb.GetPublishingWeb(SPWeb) before adding the navigation nodes. If you get the PublishingWeb before customizing the navigation everything seems to be working fine.

PublishingWeb publishingWeb = PublishingWeb.GetPublishingWeb(web);
publishingWeb.Navigation.CurrentNavigationNodes.AddAsFirst(new SPNavigationNode("Some Text", properties.ServerRelativeUrl
                                                                                                                                                   + "/Pages/media.aspx", false));
publishingWeb.Update();


And that did the trick to add a new navigation node with the above specified URL once the site is provisioned.

Refer this MSDN article for all sort of properties to modify navigation for a site. (http://msdn.microsoft.com/en-us/library/ee570519.aspx)