Home Page Link
  Skip Navigation Links
Mirrored Blogs
Information Worker > Blogs > Mirrored Blogs > Categories
Item Level Permission in SharePoint 2007

Question around Item Level permission in SharePoint 2007 came out so many times by now, well I lost the count. It is one of the most fundamental requirements of creating client centric SharePoint solutions, and it builds on concepts of Personalization and Audience Targeting, exactly where these two fail, and that is to provide appropriate security trimmings to the personalised content.

I have covered this in my Social Networking SharePoint session (among other things) at TechEd Africa this year and I decided (due to numerous requests) to post the methods and code from the presentation.

Requirement is often to make sure that people and roles with permissions to the same library don't have access to the documents/items with the same  

There is four effective ways to use Item Level Permissions in your SharePoint solutions and here they are in order of simplicity:

1. Change appropriate Item Level Permissions manually for Document/Item in a library by simply clicking on the drop down menu of the item and clicking on "Manage Permissions" option. You will be presented with a list of permissions for that item lone and options to change it for each role/user.

 

2. Second option is in also OOB (Out of the Box), used mainly when the solution should limit the access of the submitted documents (for example) in the same library to the rest of the users that have access to the same library until that item has been approved by a relevant role (note that this can be for many reasons), and it requires turning on "Require content approval for submitted items?" which can be found when navigating to Library Setting (of Document Library for Example) eg Documents(library) > Settings > Versioning Settings.

From the Help Files:

"When this content approval setting is applied, an item or file that has been changed remains in a pending state until it is approved or rejected by someone who has permission to approve it. If the item or file is approved, it is assigned an Approved status in the list or library, and it is displayed to anyone with permission to view the list or library. If the item or file is rejected, it remains in a pending state and is visible only to the people with permission to view drafts.

By default, a pending item or file is visible only to its creator and to the people with permission to manage lists, but you can specify whether other groups of users can view the item or file."

3. Automate who should have the specific permissions by means of developing a Custom Event Handler by means of SPSecurity.RunWithElevatedPrivileges Method. This method executes the specified method with Full Control rights even if the user does not otherwise have Full Control. You'll most likely use asynchronous ItemAdded event in your custom event handler.

Here‘s the sample source code:

//the following code sample removes all permissions from an item and assigns only permissions of the current user to the document

using (SPWeb web = properties.OpenWeb())

            {

                SPSecurity.RunWithElevatedPrivileges(delegate()

                {

                    using (SPSite site = new SPSite(web.Site.ID))

                    {

                        using (SPWeb impersonatedWeb = site.OpenWeb())

                        {

                            SPList impersonatedScList = impersonatedWeb.Lists[scorecardList.Title];

                            SPRoleDefinition RoleDefinition = impersonatedWeb.RoleDefinitions.GetByType(SPRoleType.Contributor);

                            SPPrincipal principal = (SPPrincipal)web.CurrentUser;

                            SPRoleAssignment RoleAssignment = new SPRoleAssignment(principal);

                            RoleAssignment.RoleDefinitionBindings.Add(RoleDefinition);

                            SPListItem impersonatedListItem = impersonatedScList.Items[properties.ListItem.UniqueId];

                                //break permission inheritance

                            if (!impersonatedListItem.HasUniqueRoleAssignments)

                            {

                                impersonatedListItem.BreakRoleInheritance(true);

                            }

 

                            SPRoleAssignmentCollection roleCollection = impersonatedListItem.RoleAssignments;

                            foreach (SPRoleAssignment assignment in roleCollection)

                            {

                                assignment.RoleDefinitionBindings.RemoveAll();

                                assignment.Update();

                            }

 

                            impersonatedListItem.RoleAssignments.Add(RoleAssignment);

                            impersonatedListItem.Update();

                        }

                    }

                });

}

 

4. Same as number 3 however this example uses proper SharePoint Impersonation to impersonate the System Account. "Why?" you might ask, well because number 3 (above) does not always work and doesn't seem to always have the absolute privileges like it promises, hence why I strongly recommend you use this option, just to be on a safe side.

Here's the sample source code:

//the following code sample also removes all permissions from an item and assigns only permissions of the current user to the document

using (SPWeb web = properties.OpenWeb())

            {

                SPUser user = web.Users["SHAREPOINT\\SYSTEM"];

                SPUserToken token = user.UserToken;

                SPSite impersonatedSiteColl = new SPSite(web.Url, token);

                using (SPWeb impersonatedWeb = impersonatedSiteColl.OpenWeb())

                {

                    SPList impersonatedScList = impersonatedWeb.Lists[scorecardList.Title];

                    SPRoleDefinition RoleDefinition = impersonatedWeb.RoleDefinitions.GetByType(SPRoleType.Contributor);

                    SPPrincipal principal = (SPPrincipal)web.CurrentUser;

                    SPRoleAssignment RoleAssignment = new SPRoleAssignment(principal);

                    RoleAssignment.RoleDefinitionBindings.Add(RoleDefinition);

                    SPListItem impersonatedListItem = impersonatedScList.Items[properties.ListItem.UniqueId];

 

                    if (!impersonatedListItem.HasUniqueRoleAssignments)

                    {

                        impersonatedListItem.BreakRoleInheritance(true);

                    }

 

                    SPRoleAssignmentCollection roleCollection = impersonatedListItem.RoleAssignments;

                    foreach (SPRoleAssignment assignment in roleCollection)

                    {

                        assignment.RoleDefinitionBindings.RemoveAll();

                        assignment.Update();

                    }

 

                    impersonatedListItem.RoleAssignments.Add(RoleAssignment);

                    impersonatedListItem.Update();

                }

            }

 

Please note that the two code samples above (in case of required automation) belong in a properly deployed Custom Event Handler and NOT a Workflow. Although it might be tempting for those that are familiar with Workflow design and not familiar with Event Handlers to use the fact that each deployed workflow support activation on item added, please resist the temptation and adhere to best practices, otherwise you're causing unnecessary resource overhead and introducing a really bad design into your solution.

Patterns and Practices -> SharePoint Guidance

My work is often advising architects and developers and providing them with proper guidance around SharePoint Products and Technologies.

Document that can greatly help those of you out there that want to know more in this regard (and that I recommend) is the latest SharePoint Guidance - November 2008

You can read more on the guidance here: http://msdn.microsoft.com/en-us/library/dd203468.aspx

This guidance discusses the following:

  • Architectural decisions about patterns, feature factoring, and packaging.
  • Design tradeoffs for common decisions many developers encounter, such as when to use SharePoint lists or a database to store information.
  • Implementation examples that are demonstrated in the Training Management application and in the QuickStarts.
  • How to design for testability, create unit tests, and run continuous integration.
  • How to set up different environments including the development, build, test, staging, and production environments.
  • How to manage the application life cycle through development, test, deployment, and upgrading.
  • Team-based intranet application development.

The following areas are not discussed in the current version of this guidance:

  • Content-oriented sites that use Web content management
  • Internet and enterprise-scale SharePoint applications
  • Multilingual SharePoint applications
  • Scale or security testing of SharePoint applications
Updating ListView Web Part Views in SharePoint 2007
Recently I got a question about a similar task that I had earlier last year and it involved a case where there were many (and I mean many) SharePoint 2007 sites and subsites containing webparts that had views showing certain SharePoint list information. However customer later realised that they needed the webpart views to contain the same view as the default view of the SharePoint list. So they asked if this can be done somehow automatically as a lot of time would be wasted updating each and every web part view manually (considering the amount of sites).Well since, like I said in the beginning, people in community started asking about the same thing I decided to share the piece of code that can do this for you.I suggest you write a code to iterate through every site, in my example below I’m just opening a particular site on my VM.            

 

            SPWeb web = new SPSite("http://starscream/").OpenWeb();
            SPLimitedWebPartManager wm = web.GetLimitedWebPartManager("default.aspx", System.Web.UI.WebControls.WebParts.PersonalizationScope.Shared); // If you have Publishing enabled I suggest you replace “default.aspx” with “Pages/Default.aspx” or whatever your default publishing page is, if this varies between different sites you should check before declaring a SPLimitedWebPartManager  for example: web.GetFile("default.aspx").Exists
            SPList list = web.Lists["Some Document Library"];
            foreach (System.Web.UI.WebControls.WebParts.WebPart webPart in wm.WebParts)       
            {
                if (webPart.GetType().Name == "ListViewWebPart" && webPart.Title == "Some Document Library")
                    {
                        ListViewWebPart myWebPart = (ListViewWebPart)webPart;
                        SPView doclibview = list.Views["All Documents"]; //actual view
                        Guid guid = new Guid(myWebPart.ViewGuid);
                        SPView webPartView = list.Views[guid];
                        webPartView.ViewFields.DeleteAll(); // deleting the existing view fields for adding new one
                        foreach (string strField in doclibview.ViewFields)
                        {
                            webPartView.ViewFields.Add(strField);
                        }
                        webPartView.Query = doclibview.Query;
                        webPartView.RowLimit = doclibview.RowLimit;
                        webPartView.ViewEmpty = doclibview.ViewEmpty;
                        webPartView.ViewFooter = doclibview.ViewFooter;
                        webPartView.ViewHeader = doclibview.ViewHeader;
                        webPartView.Scope = doclibview.Scope;
                        webPartView.GroupByFooter = doclibview.GroupByFooter;
                        webPartView.GroupByHeader = doclibview.GroupByHeader;
                        webPartView.Update();
                        myWebPart.ViewGuid = webPartView.ID.ToString("B").ToUpper();
                        myWebPart.Visible = true;
                        myWebPart.Title = "Some title";// you can change the title or leave it as it was before

                        wm.SaveChanges(myWebPart);
                        web.Update();
                    }
                    
            }

 

Multiple RSS Aggregator Web Part Example

Ok so............. long time ago, in a city far far away (from Cape Town) our very own Willy (http://dotnet.org.za/willy) wanted to re-launch SAArchitect (http://www.saarchitect.net/) community and envisaged a need to aggregate all the feeds from SAArchitect community members and filter on a certain tag in the blog posts posted by those same members (in particular "SAArchitect" tag).  Since http://www.saarchitect.net/ is running on a SharePoint 2007 platform, he needed a SharePoint kind of guy that can make this idea a reality. He searched high and low, and after being bounced around a bit he found me :), and considering the fact that at that time I thought I might have some free time between 3am and 4am every 4th day I thought, why the hell not. So Willy even blogged about it to make sure that my commitment stayed public (http://dotnet.org.za/willy/archive/2008/02/20/sa-architect-re-launching-the-community-why-how-and-where-next.aspx).

I wrote the Web Part and sent it to Willy, and although he successfully tested it, he still didn't get around to deploying it (hosting company issues I think).

After all this time I decided to share this with the community, as this is quite cool for community sites powered by SharePoint 2007, and I'm sure someone else might also find it quite useful.

I needed first to know how to get a simple, single RSS feed to display its data so I found this example from Sahil (http://blah.winsmarts.com/2006-7-Sharepoint_Webparts_AS_-_Writing_the_WebParts_-_The_RSS_Feed_WebPart.aspx) and used it as a starting point.

The way this works is that you can specify multiple feeds (separated by a character ";"), and the filter criteria as well the number of feeds displayed. This was my first shot at it, and it's quite simple, so feel free to take it apart, and I think this concept has quite a bit of potential so I think I'll revisit this once again (when I find time) with even more exciting technology.

Be careful as the example uses "saarchitect" as default value to filter on, make sure to change that when you deploy the web part, or you can even take out that whole concept out of the code.

It was written with Visual Studio 2005 SP1 with VSeWSS 1.1 (beta I think).

You can download the project files + source code with a wsp here (http://dotnet.org.za/blogs/zlatan/RSSWebPart.zip).

It used standard references (Microsoft.SharePoint, System, System.Web, System.XML)

Here's the 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;

using System.Collections.Generic;

using System.Xml;

using System.Text.RegularExpressions;

using System.ComponentModel;

 

namespace RSSWebPart

{

    [Guid("c4cc9fd1-2865-4d28-9e33-6e2f80eb4868")]

    public class RSSWebPart : System.Web.UI.WebControls.WebParts.WebPart

    {

        public RSSWebPart()

        {

            this.ExportMode = WebPartExportMode.All;

        }

        private string rssUrl;

        private string feedName;

        private const string constDefFeedCriteriaValue = "saarchitect";

        private string filterCriteria = constDefFeedCriteriaValue;

        private const string constDefFeedLimitValue = "5";

        private string feedLimit = constDefFeedLimitValue;

        private int feedLmt;

        private string tagValue;

 

 

        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;

           

            foreach (RssItem singleRssItem in feed)

            {

                if (i < feedLmt)

                {

                    if (filterCriteria != null && singleRssItem.Tags != null)

                    {

                        tagValue = singleRssItem.Tags.ToLower();

                        if (tagValue.Contains(filterCriteria) == true)

                        {

                            writer.Write("

");

                            writer.Write("

                            writer.Write(singleRssItem.Href);

                            writer.Write("\">");

                            writer.Write(singleRssItem.Title);

                            writer.Write("");

 

                            writer.Write("

");

                            writer.Write(singleRssItem.Body);

                            writer.Write("

");

                            writer.Write("

");

 

                            writer.Write("

");

                            writer.Write(singleRssItem.Tags);

                            writer.Write("

");

                            writer.Write("

");

 

                            writer.Write("

");

                            writer.Write(singleRssItem.PubDate.ToString());

                            writer.Write("

");

                            writer.Write("

");

                            i++;

                        }

                    }

                }

            }

        }

 

        public string FeedName

        {

            get

            {

                return feedName;

            }

            set

            {

                feedName = value;

            }

        }

 

 

        [WebBrowsable(true),

        Personalizable(true),

        Category("RSS Aggregator Web Part"),

        DisplayName("URLs of the Feed"),

        WebDisplayName("URLs of the Feed"),

        Description("Please enter the URLs of the feed separated by ';' character.")]

        public string FeedURL

        {

            get

            {

                return rssUrl;

            }

            set

            {

                rssUrl = value;

            }

        }

 

        [WebBrowsable(true),

        Personalizable(true),

        Category("RSS Aggregator Web Part"),

        DisplayName("Filter Criteria"),

        WebDisplayName("Filter Criteria"),

        Description("Please enter the tag value you wish to filter on for desired RSS feeds."),

        DefaultValue(constDefFeedCriteriaValue)]

        public string FilterOn

        {

            get

            {

                return filterCriteria.ToLower();

            }

            set

            {

                filterCriteria = value.ToLower();

            }

        }

 

        [WebBrowsable(true)]

        [Personalizable(true),

        Category("RSS Aggregator Web Part"),

        DisplayName("Feed Limit"),

        WebDisplayName("Feed Limit"),

        Description("Defines the list the web part will read from."),

        DefaultValue(constDefFeedLimitValue)]

        public string FeedLimit

        {

            get

            {

                return feedLimit;

            }

            set

            {

                feedLimit = value;

            }

        }

 

    }

 

 

    internal class RssFeed : List

    {

        private XmlDocument rssDoc;

 

        internal RssFeed(string RssURL)

        {

 

            if (RssURL == null)

            {

                this.Add(new RssItem());

            }

            else

            {

                string[] rssUrlsArray = RssURL.Split(new char[] { ';' });

                foreach (string url in rssUrlsArray)

                {

                   

                    try

                    {

                        rssDoc = new XmlDocument();

                        XmlTextReader xRead = new XmlTextReader(url);

                        rssDoc.Load(xRead);

 

                        XmlNodeList xNodes = rssDoc.SelectNodes("./rss/channel/item");

                       

                        foreach (XmlNode xNode in xNodes)

                        {

                            

                            this.Add(new RssItem(xNode));

                           

                        }

                       

                    }

                    catch (Exception)

                    {

                        this.Add(new RssItem());

                    }

                }

            }

        }

    }

 

    internal class RssItem

    {

        private string title;

        private string href;

        private string body;

        private string tags;

        private DateTime pubDate;

 

 

        public string Href

        {

            get { return href; }

        }

 

 

        public string Title

        {

            get { return title; }

        }

 

        internal RssItem()

        {

            title = "Feed not 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; }

        }

 

        internal RssItem(XmlNode xNode)

        {

            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;

            }

        }

 

        public string FixDesc(object desc, object link)

        {

            if (link == null || desc == null) return String.Empty;

 

            string description = desc.ToString();

            //Replace all HTML tags so none get cut-off and screw up the page

            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) + " ... More";

 

            }

            return stripDesc;

        }

    }

}

How to use Web Part Custom Properties in SharePoint 2007 and WSS 3.0

It's so weird how so many people ask you the same thing around the same time sometimes, anyway I've had some request around on how to create custom properties for Web Parts in SharePoint, more to the point, on how to get them to categorise and appear in the "Modify Web Part" panel.

It's quite simple actually, just declare the properties and decorate them with attributes like in the following example:

        [WebBrowsable(true),

        Personalizable(true),

        Category("RSS Aggregator Web Part"),

        DisplayName("URLs of the Feed"),

        WebDisplayName("URLs of the Feed"),

        Description("Please enter the URLs of the feed separated by ';' character.")]

        public string FeedURL

        {

            get

            {

                return rssUrl;

            }

            set

            {

                rssUrl = value;

            }

        }

 

Please note that Category attribute will basically create section for all your properties that carry that attribute value and WebDisplayName will be the name of the property appearing on the panel.

Using PeopleEditor Control with Web Parts in SharePoint 2007/WSS 3.0

Ever wanted to borrow that cool AJAX like control in SharePoint 2007 (or WSS 3.0) that lets you pick and resolve users so that you can manage those users/groups and their  permissions.

The control I'm talking about is PeopleEditor (aka People Picker) and there's not much documentation out there, and the examples are not very helpful.

At some point in time last year I decided to investigate this control and find out how to get resolved items out of it, as I needed to use it and abuse it for a component of a SharePoint solution at the time.

I got some questions recently about it, so I promised that I will post a very simple example on how to use it, so here it goes:

This web part in a very crude (not recommended) way filters out the groups with permissions on a Task list on the web and allows for adding/removing users through PeopleEditor control to groups selected through the dropdown control.

(Please note that this is just to show a proof of concept, do not use this web part as is in production)

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 PplEdtr
{
    [Guid("4114de9b-ae5c-45a4-b1c0-b8e4abf4675e")]
    public class PplEdtr : System.Web.UI.WebControls.WebParts.WebPart
    {
        public PplEdtr()
        {
            this.ExportMode = WebPartExportMode.All;
        }

        private Label dropDownListLabel;
        private DropDownList dropDownList;
        private PeopleEditor peopleEditor;

        private Button buttonAddUser;
        private Button buttonRemoveUser;
        private SPList taskList;

        private string html = null;

        protected override void CreateChildControls()
        {
            base.CreateChildControls();

            string groupName = null;

            this.dropDownListLabel = new Label();
            this.dropDownList = new DropDownList();


            using (SPWeb web = SPContext.Current.Web)
            {
                taskList = web.Lists["Tasks"];
                this.dropDownList.Items.Clear();
                this.dropDownListLabel.Text = "Select the group where you want to add the desired user for the Task List: " + taskList.Title + " ";
                foreach (SPRoleAssignment role in taskList.RoleAssignments)
                {
                   
                    bool isGroup = true;
                    try
                    {
                        SPGroup group = taskList.Lists.Web.Groups[role.Member.Name];
                        groupName = group.Name;
                    }
                    catch (Exception ex)
                    {
                        isGroup = false;
                    }
                    if (isGroup == true)
                    {
                        ListItem listItem = new ListItem();
                        listItem.Text = groupName;
                        listItem.Value = groupName;
                        this.dropDownList.Items.Add(listItem);
                    }
                }
            }
            this.peopleEditor = new PeopleEditor();

            this.Controls.Add(peopleEditor);

            this.buttonRemoveUser = new Button();
            this.buttonAddUser = new Button();
            this.buttonAddUser.Text = "Add a User to the Selected Group";
            this.buttonRemoveUser.Text = "Remove a User from the Selected Group";

            this.buttonAddUser.Click += new EventHandler(buttonAddUser_Click);
            this.buttonRemoveUser.Click += new EventHandler(buttonRemoveUser_Click);
           
            this.Controls.Add(this.dropDownListLabel);
            this.Controls.Add(this.dropDownList);
            this.Controls.Add(this.buttonAddUser);
            this.Controls.Add(this.buttonRemoveUser);
        }

        private void buttonAddUser_Click(object sender, EventArgs e)
        {
            foreach (PickerEntity entity in peopleEditor.ResolvedEntities)
            {
                if (entity.IsResolved == true)
                {
                    try
                    {
                        SPGroup group = taskList.Lists.Web.Groups[dropDownList.SelectedItem.Value];

                        bool isPresent = false;
                        foreach (SPUser groupUser in group.Users)
                        {
                            if (groupUser.LoginName == entity.DisplayText)
                                isPresent = true;
                        }
                        if (isPresent == false)
                        {
                            group.AddUser(entity.DisplayText, null, null, null);
                            group.Update();
                            html = html + "
The selected User: " + entity.DisplayText + " has been added to the Group: " + group.Name + "";
                        }
                        else
                            html = html + "
The selected User: " + entity.DisplayText + " already exists in the Group: " + group.Name + "";
                    }
                    catch (Exception ex)
                    {
                        html = html + "
" + ex.Message + "";
                    }
                }
                else
                    html = html + "
Entity " + entity.DisplayText + " is not resolved, please ensure it's resolved before you procede" + "";
            }
            this.dropDownListLabel.Text = html;
        }

        private void buttonRemoveUser_Click(object sender, EventArgs e)
        {

            foreach (PickerEntity entity in peopleEditor.ResolvedEntities)
            {
                if (entity.IsResolved == true)
                {
                    try
                    {
                        SPGroup group = taskList.Lists.Web.Groups[dropDownList.SelectedItem.Value];

                        bool isPresent = false;
                        foreach (SPUser groupUser in group.Users)
                        {
                            if (groupUser.LoginName == entity.DisplayText)
                            {
                                SPUser user = group.Users[entity.DisplayText];
                                isPresent = true;
                                group.RemoveUser(user);
                                group.Update();
                                html = html + "
The selected User: " + entity.DisplayText + " has been deleted from the Group: " + group.Name + "";
                            }
                        }
                        if (isPresent == false)
                            html = html + "
The User: " + entity.DisplayText + " does not exist in the selected Group: " + group.Name + "";

                    }
                    catch (Exception ex)
                    {
                        html = html + "
" + ex.Message + "";
                    }

                }
                else
                    html = html + "
Entity " + entity.DisplayText + " is not resolved, please ensure it's resolved before you procede" + "";
            }
            this.dropDownListLabel.Text = html;
           
        }
    }
}

You can download the source code here (http://dotnet.org.za/blogs/zlatan/PplEdtr.zip)

This was done (in a huge rush) using the following:

Visual Studio 2005

SharePoint 2007/WSS 3.0 SDK 1.3

Visual Studio Extensions for SharePoint 1.1

Developing Basic Web Parts in SharePoint 2007

Many times in the past I've been asked to help and elaborate on one SharePoint topic and that is building Web Parts for SharePoint. I've talked about this in my community events as well as conferences where I presented. I've also blogged about some more advanced development of Web Parts but I've never done a more basic explanation of how to develop simple Web Parts. After this last request I finally gave in, so here it is.

Coolest thing about web parts in SharePoint is its complete utilisation of ASP.NET 2.0 platform and what it has to offer. SharePoint web pages are basically a combination of the precompiled DLL and a ASPX page. If you change and/or customize a page in SharePoint the changes are stored in the database, so the final ASPX page that you see is a combination of the original ASPX page and changes stored in a database.

 

Getting to the point of WebParts, webparts can be insanely easy to be make or they can drive you crazy if they're way too complex.

Very easy way to create (with AJAX) is actually described in my post which is actually done in VS2005 ( http://dotnet.org.za/zlatan/archive/2007/10/12/developing-ajax-web-parts-in-sharepoint-2007.aspx). Example also contains source code of the webpart I designed to show new tasks from the SharePoint task list as they arrive (without the need to refresh), this code can also be used to rotate news or other list items dynamically and many other things.

If you're not interested in using AJAX in your webparts then just ignore the instructions 1-3 and go to 4 (which is the very beginning of the code):

First, make sure you're using:

Visual Studio 2005 with Office SharePoint Server 2007 SDK 1.3 (or Windows SharePoint Services SDK 1.3) and Visual Studio 2005 extensions for Windows SharePoint Services 1.1.

http://dotnet.org.za/zlatan/archive/2008/03/09/sharepoint-server-2007-version-1-3-and-wss-3-0-version-1-3-available.aspx

http://dotnet.org.za/zlatan/archive/2008/02/13/final-release-of-vsewss-1-1-visual-studio-extensions-for-windows-sharepoint-services.aspx

You can also develop Web Parts with Visual Studio 2008, but without the templates (for the time being) that do help a lot, especially if you're a beginner.

 

1. Start the VS choose Web Part (template) under SharePoint section.

 

2. SharePoint WebPart inherits from an abstract base class called Microsoft.SharePoint.WebPartPages.WebPart, which inherits from System.Web.UI.WebParts.WebPart, so since you got two classes to choose from, which one do you choose?

Safe bet is the ASP.NET 2.0 abstract class, ie. System.Web.UI.WebControls.WebParts.WebPart. Anyway, that's the one that you'll see when your template loads.

 

3. You would be presented with the code below:

Next you override CreateChildControls to create the control tree, later override any other method from the System.Web.UI control class.

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 WebPart1
{
    [Guid("720e3e34-4127-438b-a4fb-d159d5a082e7")]
    public class WebPart1 : System.Web.UI.WebControls.WebParts.WebPart
    {
        public WebPart1()
        {
        }

        protected override void CreateChildControls()
        {
            base.CreateChildControls();

            // TODO: add custom rendering code here.
            // Label label = new Label();
            // label.Text = "Hello World";
            // this.Controls.Add(label);
        }
    }
}

 

4. Press F5 and when the Web Part is deployed add it on the SharePoint 2007 page from the library (if you don't specify otherwise then you'll find it under "Miscellaneous")

If you're using any earlier SDK or extensions, once you compile your WebPart Project follow these steps to deploy the solution:

1. First drag and drop the compiled assembly into the GAC (by default c:\windows\assembly).
2. Open the properties of the dll to get the public key token.
3. Now register the safe control in the web.config. (i.e. '1.0.0.0, Culture=neutral, PublicKeyToken=74e5f216d6256126" Namespace="WebPartForYou" TypeName="*" Safe="True" /> )

4. In SharePoint, click 'Site Actions', 'Site Settings' and then under 'Site Collection Administration' click 'Go to top level site settings'.
5. Under 'Galleries', click 'Web Parts'. Then click 'New'.
6. Now, the new webpart(s) will appear in the list. If not, try an IISRESET and refresh the page.
Select the webpart we've just created and click 'Populate Gallery'.

Now when you edit your SharePoint page you'll find your WebPart listed, most likely in Miscellaneous section, click to Add it and Voila.

 (note that if you're using the above SDKs and extensions, all of these steps above are done automatically for you).

Hope that this helps, it should get you started

Building OBAs with WPF, WCF, and LINQ

One thing is for sure, using Visual Studio Tools for Office in the new Visual Studio 2008 environment has become much easier and a lot more effective.  We have a number of frameworks that not only make our lives as developers easier but it also allows us to create even more powerful solutions. Besides the mighty Enterprise Content Management platform MOSS 2007, simple Office applications like MS Word can utilise Business Process Management, SOA and Enterprise Service Bus concepts, even employ more attractive User Interface to elevate user experience and create large powerful enterprise solutions.

The powerful frameworks that I'm talking about are Windows Workflow Foundation, Windows Communication Foundation, and Windows Presentation Foundation. Just Windows Workflow Foundation is so powerful that for example a new version of the mighty BizTalk Server will be rewritten on it (well the orchestration engine).

Another great thing is how well these frameworks work with each other and with the rest of the MS technologies. Most of the large enterprises are used to using office application over the past two decades, so extending the functionality of the same familiar interface to utilise the functionality of the modern Enterprise Content Management systems is now easier than ever and also the next logical step in the evolution of large Enterprise Solutions.

Also, as XML is the common language between all of these technologies using LINQ is almost always a must when it comes to developing such solutions.

The architectural concept behind this is commonly known as Office Business Applications (as most of you know).

Anyway the main reason for this post is this excellent article (http://msdn.microsoft.com/msdnmag/issues/07/12/VstoNet/default.aspx) with downloadable source code (above you can see the downloaded code from the article in action on my laptop) that shows:

  • How VSTO makes Office development more powerful
  • Using WCF, WPF, and LINQ in Office solutions
  • Easily adding advanced features to your Office apps
  • Building services the easy way

Also I suggest checking what Soma Somasegar (VP, Development Division Microsoft) posted on Office development recently. Here's the link: 

http://blogs.msdn.com/somasegar/archive/2008/01/30/integrating-business-systems-with-office-and-sharepoint.aspx

Getting Roles and Permissions on a List/Document Library Level in SharePoint 2007 (or WSS 3.0)

So let’s say you’re building a web part or a custom SharePoint (server/services) page and you need to know what roles are there on a particular list or even object so that you control what is being showed to the user, hide or show relevant information etc (example: http://blogs.msdn.com/modonovan/archive/2005/07/07/436394.aspx).

If you’re a seasoned SPS veteran you’ll first go for the SPRole (http://msdn2.microsoft.com/en-us/library/microsoft.sharepoint.sprole.aspx) and SPRoleCollection (http://msdn2.microsoft.com/en-us/library/microsoft.sharepoint.sprolecollection.aspx) which you’ll soon learn, as your trusty VS 2008 will inform you, has become obsolete, but it will let you use it.

So you probably would’ve used it like this:

                    SPWeb currentWeb = SPControl.GetContextWeb(Context);

                    foreach (SPRole role in currentWeb.Roles)

                    {

                        //I guess you would put your code here

                        Console.WriteLine(role.Name);

                    }

Then you remember how limiting is was and you wonder, well if this is obsolete, what has replaced it?

Well this is what:

SPRoleAssignment (http://msdn2.microsoft.com/en-us/library/microsoft.sharepoint.sproleassignment.aspx )

SPRoleAssignmentCollection (http://msdn2.microsoft.com/en-us/library/microsoft.sharepoint.sproleassignmentcollection.aspx)

Examples of RoleAssignments:

            using (SPSite site = new SPSite("http://yourspsite/"))

            {

                using (SPWeb web = site.OpenWeb())

                {

                    SPList yourList = web.Lists["Your List Name"];

 

                 

                    foreach (SPRoleAssignment role in yourList.RoleAssignments)

                    {

                        //role.Member gives you the SPPrincipal type object, which is a user or a group, .Name gives you the Name of the User/Group

                        Console.WriteLine(role.Member.Name);

                        //here you can add your code which might include Add() and Update() of the RoleAssignments Collection (yourList.RoleAssignments)

                    }

                }

            }

            using (SPSite site = new SPSite("http://yourspsite/"))

            {

                using (SPWeb web = site.OpenWeb())

                {

                    SPList yourList = web.Lists["Your List Name"];

 

                    //the output will look something like this :

                    //

                    //

                    //

                    //

                    // this gives you users and/or groups and their security masks

                    Console.WriteLine(yourList.RoleAssignments.Xml);

 

                    //you can use LINQ to parse and iterate through the xml

                    XElement listGroupIDs = XElement.Parse(yourList.RoleAssignments.Xml);

 

                    foreach (XElement x in listGroupIDs.Elements("permission"))

                    {

                        //extract the values and use them to find and/or instantiate the values of groups and objects and even manipulate them

                        Console.WriteLine(x.Attribute("memberid").Value);

                    }

                }

            }

Although the following two classes are considered to be obsolete:

SPPermission (http://msdn2.microsoft.com/en-us/library/microsoft.sharepoint.sppermission.aspx)

SPPermissionCollection (http://msdn2.microsoft.com/en-us/library/microsoft.sharepoint.sppermissioncollection.aspx)

 There is one really cool thing about SPPermissionCollection in particular which is its XML property which is a bit more descriptive then the same property from the SPRoleAssignmentCollection class.

Example:

            using (SPSite site = new SPSite("http://yourspsite/"))

            {

                using (SPWeb web = site.OpenWeb())

                {

                    SPList yourList = web.Lists["Your List Name"];

 

                    //the output will look something like this :

                    //

                    //

                    //

                    //

                    //

                    //which gives you Group/UserNames and not just MemberIDs,

                    Console.WriteLine(yourList.Permissions.Xml);

 

                    //you can use LINQ to parse and iterate through the xml

                    XElement listGroupIDs = XElement.Parse(yourList.Permissions.Xml);

 

                    foreach (XElement x in listGroupIDs.Elements("Permission"))

                    {

                        //extract the values and use them to find and/or instantiate the values of groups and objects and even manipulate them

                        Console.WriteLine(x.Attribute("GroupName").Value);

                    }

                }

            }

 

When CopyTo() and CopyFrom() just don't cut it anymore

When it come to copying of items to and from different locations (in SharePoint) by means of using SharePoint object model, first obvious methods you find (and try using) are CopyTo() and CopyFrom(). They all seem nice and dandy if you’re simply just copying an item, but when it comes to some slightly more complex cases, such as, copying an item that contains major/minor versions, with check in/check out functionality or even copying to a folder where an item like this already exists, you soon realise that the above mentioned methods are sooo rubbish/useless. You don’t believe me?? Use a Reflector tool to find out, it will be far clearer.

In my case, one small part of the required functionality as per our design of the SharePoint 2007 solution required copying of a file to a document library where that file might already exists and the copied file must then be version on top of that existing file, we’re using major versions here only (confused, I apologise, try and read it again slowly, I’m too lazy to re-phrase). Anyway so basically what needed to be done is to first CheckOut the item if the item exists (and if it requires checking out) and then copy a file from the origin to a destination file as a new version (one would expect this to be done by default).

Then I started exploring all the alternatives, until my friend Rupert pointed out the OpenBinary and SaveBinary functionality and it worked, just as expected, I never turned back.

Here’s pretty much what the code looked like:

//getting the list object of the target list

                SPList nextList = web.Lists[destinationListNameValue]; //web is SPWeb web

               

                SPListItemCollection newListItems = nextList.Items;

                foreach (SPListItem newListItem in newListItems)

                {

//looking for a list item that is named the same way as the document name of the document that is being copied (documentName) 

                    if (documentName == newListItem["Name"].ToString())

                    {

//impersonatedItem is the impersonated (I had my reasons for needing to use impersonation here, you probably won’t have to) SPListItem of the document that is being copied and newListItem is the SPListItem of the target document 

                        Byte[] fileContent = impersonatedItem.File.OpenBinary();

                        newListItem.File.SaveBinary(fileContent);

                    }

                }

(Please Note that you need to have Microsoft.SharePoint referenced in your project and include – using Microsoft.SharePoint)

 

Here’s someone else also dealing with the whole CopyTo() and CopyFrom() issue:

 

http://k2distillery.blogspot.com/2007/10/copy-version-history-with_5.html

 

While on this topic, here’s also a useful article on Copying over a SharePoint list from source site to destination site:

http://blah.winsmarts.com/2007-5-Copying_over_a_SharePoint_list_from_source_site_to_destination_site.aspx

By the way, don’t get me wrong, the versatility given by CopyTo() in which you can just copy a file in a SP system  by giving full url of the file can be quick/easy and useful in some cases, but still very few.


RSS Feed RSS 2.0 Feed



1
1
1
1
Tags
1
1
1
1

1
1
1
1
1
1
1
1

Feedback