Thursday, November 15, 2012

Run with elevated privileges in SharePoint,MOSS

(Gud one that I found in other blog)
In case you didn't know, there is a construct built into SharePoint that allows developers to create code that runs as the System Account instead of the logged in user, essentially giving that user Administrator Level Permissions in a confined space. I will go over the code required to do this below, but essentially you have a block of code within your larger project that needs the logged in user to have certain permissions that they may not have, and this small block of code will then be run as the System Account, giving it the permissions needed for the task at hand.
Well, at first thought everyone I have explained this to has the same questions and concerns, “Why would you ever want to do that?” or “That is a huge security risk!”.
I could never come up with a very good example to explain it and my attempts to reassure customers that the security risk is very minimal as the user will only have permission to do exactly what the developer lets them sometimes was not well understood.
Well I finally had a project that required me to do this, so I figured I would share it to give a fairly simple real world example.
Project Objective: Create an extranet to serve as a customer support site where users can log Service Requests, manage their account, order new products, etc. via the web or by phone.
This is fairly simple and something I have done several times for different customers, but this project had one difference. Service / Support Requests could be made by phone, where all of my other projects were strictly web oriented. Does anyone see the problem this raises yet? Well I eventually incorporated the Cisco phone system into the site to generate Service Requests, but that is not what I am talking about. With any system like this, it is vital that customers only have access to their own Service Requests (as in they cant view other user’s requests).
Typically, when using a SharePoint list one can turn on the settings in the Advanced Settings section of a List (seen below) so that users can only view and edit their own List Items. This is very handy and works very well when users are always the creator of their own items, but in this case when someone calls in, someone else will be creating the service request for them… see the problem? Well, I thought about trying to change the Created By field to the user that called in, but decided it would be a neat place to use the elevated permissions approach.

The Solution: So, this is the summary of what I did. I didn’t give any customers permissions to the Service Request List at all from within SharePoint. All access that customers had to that List was done through custom forms and web parts that made use of the elevated permission construct. This ended up being 3 forms and 3 web parts that used Elevated Permissions. Customers would use one form to create a Service Request, another to view it, another to edit it and then three web parts to display the contents of the list on various pages.
I added a custom text field to the list called Customer ID which would store each customer’s unique ID, detailing who each Service Request belonged to. The custom forms that users would use would populate this field upon creation by looking to see who the current user was, and looking up their ID in another List. Likewise when a member of the support staff was creating a service request received over the phone, they would fill in the Customer’s ID before creating it (The phone system was later used to automate this). This way, we are not relying on the Created Field to limit what each user is allowed to see.
Below I will go through the basics of how Elevated Permissions work and then show in more detail how I used it in my solution. Then in the next few days I hope to stick out a web part that incorporates it as well.
This is the basic code snippet you need to run with elevated permissions:
private void yourFunction()
{
      // Non-Elevated Permission Code Goes Here

      SPSecurity.RunWithElevatedPrivileges(delegate()
      {
            // Elevated Permission Code Goes Here
      });    

      // Non-Elevated Permission Code Goes Here
}
Pretty much everything you find online about this has code that is poorly explained, so hopefully I can do a decent job and make it easy. The code above is simple enough right? Well here is one place people routinely run into problems. If you are using an instance of SPWeb or SPSite before your Elevated Permission Code block, you won’t be able to use it. You need to get a new instance of the SPWeb or SPSite object to use once you enter the elevated block. Below is the code that I use to do this.
private void yourFunction()
{
      SPSite site = SPContext.Current.Site;
      SPWeb web = SPContext.Current.Web;

      SPSecurity.RunWithElevatedPrivileges(delegate()
      {
            using (SPSite ElevatedSite = new SPSite(site.ID))
            {
                  using (SPWeb ElevatedWeb = ElevatedSite.OpenWeb(web.ID))
                  {
                        // Code Using the SPWeb Object Goes Here
                  }
            }
       });
}
I am pretty sure that little tidbit cost me about a day the first time I tried to play with Elevated Permissions, so hopefully that will help some of you out. After that, it is really simple as you just put your code in the middle of it just like you would if you weren’t using the elevated permissions.
As further example, in my NewSR.aspx form that users go to when creating a new Service Request, I use a runWithElevatedPrivileges block in two functions. The first is a private function I call within the OnPreLoad() function called LoadData(). Inside this function I am populating drop down menus from data in a SharePoint list for the Priority of the service request and the products that are affected.
The second function with a runWithElevatedPrivileges block is my onSubmit() function that is called when a user clicks the submit button.

So it is actually pretty simple. The only other thing I am going to demonstrate is how I made the view and Edit Forms Secure. As you probably know, every List Item has an integer ID (.ID) and a unique guid ID (.UniqueID). Well, the custom forms I made for view and edit look in the querystring for a guid which it then uses to look up the Service Request. (If you can guess the guid of another service request, well you broke my security but it seems quite unlikely) There isn’t anything fancy about accessing the querystring to get the guid and look up the Service Request, but I thought it would be handy to store a link to the item within the item itself as an additional field. This makes it easy to email the user a link to view their service request among other things.
So I created a text field called Link and populated it as shown below.
private void yourFunction()
{
      SPSite site = SPContext.Current.Site;
      SPWeb web = SPContext.Current.Web;

      SPSecurity.RunWithElevatedPrivileges(delegate()
      {
            using (SPSite ElevatedSite = new SPSite(site.ID))
            {
                  using (SPWeb ElevatedWeb = ElevatedSite.OpenWeb(web.ID))
                  {
                        srList = ElevatedWeb.Lists["Service Requests"];
                        SPListItem newItem = srList.Items.Add();
                     
                        // Do stuff to create the list item

                        ElevatedWeb.AllowUnsafeUpdates = true;
                        newItem.Update();
                        Guid temp = newItem.UniqueId;
                        newItem["Link"] = "<DIV><a href=\"https://YourSite.com/_layouts/custom/ViewSR.aspx?ID=" + temp.ToString("d") + "\">View SR</a></DIV>";
                        newItem.Update();
                        ElevatedWeb.AllowUnsafeUpdates = false;
                  }
            }
       });
}
The tricky part here is having to call item.update() twice. You have to call it twice because the first time you call it is when the list item is actually created. Before then, it does not have a Unique ID to reference. So once it is created, you can grab the Unique ID, and populate the Link field with a HTML formatted URL that references the item and can be easily inserted into a HTML based email or a page that has a content editor web part CEWP with the JavaScript in it found here. You then call update the second time to save your link field.

The use of the link field and the JavaScript found above allows me to render links in a web part as shown above.
Well, hopefully this will be useful to someone – I think it would have saved me a day or so once upon a time when I first tried to do this.

Adding your Web Part to the Safe Controls List

why we want to add webpart as safe control in SharePoint?


A fundamental assumption of the Windows SharePoint Services technology is that "untrusted users" can upload and create ASPX pages within the system on which Windows SharePoint Services is running. These users should be prevented from adding server-side code within ASPX pages, but there should be a list of approved controls that those untrusted users can use. One way to provide these controls is to create a Safe Controls list.
The Safe Controls list is a list of controls and Web Parts specific to your SharePoint site that you have designated as safe for invocation on any ASPX page within your site. You store this list in the web.config file in your Web application root.

How to add as safe control

  1. Open the web.config file in the application root.
  2. Add a safe control entry for your custom assembly to the web.config file as follows:


    <SafeControl Assembly="MyWebPartLibrary, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" Namespace="MyWebPartLibrary" TypeName="*" Safe="True" AllowRemoteDesigner="True"/>

Web part page life cycle

Main Points are:

    protected override void OnInit(EventArgs e)
    protected override void OnLoad(EventArgs e)
    protected override void CreateChildControls()
    protected override void LoadViewState(object savedState) //Only at Postback
    protected override void OnPreRender(EventArgs e)
    protected override void Render(System.Web.UI.HtmlTextWriter writer)
    protected override void OnUnload(EventArgs e)
    public override void Dispose()



      Description:

      OnInit: This method handles initialization of the control.
      OnLoad: This event handles the Load event. This is also used for initialize the control but is not intended for loading data or other processing functionality.
      CreateChildControls: This is the most popular event in web part life cycle. This creates any child controls. So if you are adding any control to display then you have to write in this method.
      EnsureChildControls: This method ensures that CreateChildControls has executed. EnsureChildControls method must be called to prevent null reference exceptions.
      SaveViewState: View state of the web part saved.
      OnPreRender: This method handles or initiates tasks such as data loading that must complete before the control can render.
      Page.PreRenderComplete: The page fires the PreRenderComplete event after all controls have completed their OnPreRender methods.
      Render: This method is used to render everything.
      RenderContents: Renders the contents of the control only, inside of the outer tags and style properties.
      OnUnload: Performs the final cleanup.

      Friday, November 9, 2012

      Cascading dropdown lists in SharePoint 2010


      Today I am going to explain you how to create a list with filtered lookup columns, based on information in previous columns. Check out SharePoint Cascaded Lookup from SharePointBoost.
      Image from SharePointBoost
      The software looks great. I haven’t tried it, but it does offer some great extra functionality.
      Unfortunately, this piece of software is very expensive for small companies that only need this for a single form on SharePoint.
      So I am going to show you how to create such a list without the need of buying this piece of software. I covered it into a lot of steps, but no programming is needed. The only things you need, are a SharePoint 2010 environment, InfoPath 2010 and this tutorial :D !
      For this small tutorial, I will create a simple room-reservation list for a company existing out of multiple physical buildings. I will not explain about how to create a reservation system, I only use it as a example to show you how to filter data based on a previous selected item.
      The result of this tutorial will be a form where you can select a physical location. After you made your selection, only those rooms for that building will be shown.
      Again, i covered this into a lot of steps. But after you have done this a couple of times, you do not need expensive software and you can create filtered lookup forms yourself!

      1. Create a Custom list called ‘buildings’.
        A Custom list is created with no extra columns except for ‘title’. We leave it like that.
      2. Add buildings to the list: ‘Building A’, ‘Building B’ and ‘Building C’.
      3. Create another Custom list called ‘rooms’.
      4. Go to the list settings of ‘rooms’ and click on ‘create column’. Create a Lookup column called ‘Building’.
        Require that the column contains information.
        Get information from: ‘Buildings’,  in this column: ‘Title’
      5. Add some rooms to this list. I created multiple rooms at each location.
      You have now created the needed lists and filled it with data, but we still need to create the room reservation form.
      1. Again, create a new Custom list called ‘reservations’.
      2. Click on ‘Create column’ and create a Lookup column called ‘Building’. Get information from: ‘buildings’,  in this column: ‘Title’
      3. Repeat step 2, but this time create a Lookup column called ‘Room’. Get information from: ‘rooms’,  in this column: ‘Title’
      4. Use Internet Explorer: Open the list settings for ‘reservations’ and click on ‘Form settings’.
        You will see a label with the text ‘Customize the current form using Microsoft InfoPath’. Click OK.
      5. The Reservations form will now be opened in InfoPath 2010.
      6. Right click on the Building field, and select properties.
        Select ‘Get choices from an external data source’ and click ‘Add…’.
        Create a connection with the following settings:
        - New connection, receive data
        - Receive data from: SharePoint library or list
        - select ‘buildings’ library
        - select the ‘id’ and ‘title’ column
        - do not check the box for making a copy of the data
        - check the box that asks for automatically retrieving data when the form is opened. Save the external data source as ‘buildings1′.
      7. At value, choose ‘ID’ and at display name, choose ‘Title’
      8. Right click on the Room field, and select properties.
        Select ‘Get choices from an external data source’ and click ‘Add…’.
        Create a connection with the following settings:
        - New connection, receive data
        - Receive data from: SharePoint library or list
        - select ‘rooms’ library
        - select the ‘id’, ‘title’ and ‘building’ column
        - do not check the box for making a copy of the data
        - do not check the box that asks for automatically retrieving data when the form is opened. Save the external data source as ‘rooms1′.
      9. At value choose ‘id’, choose ‘Title’ for  the display name.
      You are not done yet, but almost there! A little break here, to tell you what you have done in the last few steps. You created 2 data connections, retrieving data from the SharePoint lists ‘buildings’ and ‘rooms’. The data connection for buildings will load its data into the buildings form when the form is being opened. The other one won’t. Check it out, press ctrl+shift+Q for a fast publish and add a new item to the registration list. If all went well you will see something like this:

      The Room listbox should not yet contain any data.
      Now we are going to execute the final steps. In these steps you will create a filter. This filter will show only rooms for the building you selected in the field above.
      1. Click on the xPath button at the properties dialog of Room next to ‘Entries’.
        Click on the ‘Filter data’ button.
      2. Click on ‘Add’.
        In the first column, choose ‘select a field or group’. A window pops up, choose advanced view.
        - Select the ‘main’ datasource, click on ‘dataFields’ and select ‘Building’.In the second column, choose ‘equals’.In the third column, choose ‘select a field or group’. Agan a window pops up, choose advanced view.
        - Select the ‘rooms’ datasource, click on ‘dataFields’ and select ‘Building’.
        Click OK
      3. The filter will now look like ‘Building equals Building’. Now close all property dialogs.
      4. Select the building column and click on ‘Add Rule’. Select the query action when the field is changed.

        Now choose the data connection ‘rooms1′ and click OK.
      5. Again, click Building and make a new rule: When the field is being changed, set a value for a field.

        Choose field ‘Room’ and leave value empty.
      Finally! We are done. Fast publish the form to SharePoint again by pressing ctrl+shift+Q.
      Now if you carefully executed all steps above, you will see a form like this:

      Notice that only rooms will be shown that are located in that specific building.

      Connecting two webparts in SharePoint



      This tutorial describes the step to access data by connecting two different Web Parts in a SharePoint Site. In order to do so, three things should be kept in mind:
      • Provider Web Part (that provides the data)
      • Connection Interface (that provides the connection between two Web Parts)
      • Consumer Web Part ( that accepts the data)
      But before we go further, one should be aware of how to create and deploy a web part.

      Following are the steps :

      Creating a Connection Interface
      In this step, we create an interface say ‘CommunicationInterface’.  
      In this interface, we define a property ‘ parameter1’ for  providing data.  The no. of properties depends on the no. of parameter to be passed.



      //Code Part

      using System;
      using System.Collections.Generic;
      using System.Linq;
      using System.Text;


      namespace CommunicationInterface
      {
          public interface ICommunicationInterface
          {
              string parameter1 { get; }

          }
      }

      Once this interface is created, compile it and add its DLL to the Global Assembly Cache (C:\Windows\Assembly) in your  system.





      Creating a Provider Web Part
      The second step is to create a Provider Web Part to pass the data to the interface.
      Create a web part and name it say ‘WP_Provider’.  Add reference of the earlier created ‘CommunicationInterface’ DLL. 
      Once the reference is added,  implement the ‘ICommunicationInterface’ to ‘WP_Provider’ class.
      Then the connection provider property is added and the reference to the communication Interface is returned.
      Implement the property defined in the interface.

      //Code Part
      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 CommunicationInterface;

      namespace WP_Provider
      {
         
         public class 
         WP_Provider: Microsoft.SharePoint.WebPartPages.WebPart,ICommunicationInterface
          
         {
              Label nm;
              TextBox tbname;
              Button btn=new Button();
             
              RadioButtonList rb = new RadioButtonList();

             
            // Provides connection provider property for the parameters
            [ConnectionProvider("Parameter1 Provider",
                          "Parameter1 Provider")]
              public ICommunicationInterface ConnectionInterface()
              {
               // this returns a reference to the communication interface
                  return this;
              }

              protected string _parameter1 = "";


              // Property defined in Interface is implemented
              public string parameter1
              {
                  get { return _parameter1; }
              }
             
             
              public WP_Provider()
              {
             
              }

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



                  //Accessing a particular list items

                  SPSite mysitecol = SPContext.Current.Site;
                  SPWeb mysite = SPContext.Current.Web;
                  SPList mylist = mysite.Lists["UpdateList"];
                  SPListItemCollection itemcol = mylist.Items;
                 
                  foreach (SPListItem itm in itemcol)
                  {
                      string nm = itm["Company_Id"].ToString();
                      rb.Items.Add(nm);

                  }

                  btn.Text = "Send";
                  this.Controls.Add(rb);
                  this.Controls.Add(btn);
                  btn.Click += new EventHandler(btn_Click);
              }

         public  void btn_Click(object sender, EventArgs e)
              {
                  // set connection provider property with required textbox info.
                 // this._parameter1 = tbname.Text;
                  this._parameter1 = rb.SelectedItem.Text;
              }

          }
      }

      After completing the code, compile and add the DLL in the Global Assembly Cache (C:\Windows\Assembly).
      Create the corresponding ‘dwp’ file and add the SafeControl in the web.config of SharePoint Site.



      Creating a Consumer Web Part
      The third step is to create a Consumer  Web Part to pass the data to the interface.
      Create a web part and name it say ‘WP_Consumer’.  Add reference of the earlier created ‘CommunicationInterface’ DLL. 
      Then the connection Consumer property is added and the reference to the communication Interface is retrieved.
      From this reference, the parameter that is passed from Provider Web Part is obtained.

      //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 CommunicationInterface;

      namespace WP_Consumer
      {
         
          public class WP_Consumer : Microsoft.SharePoint.WebPartPages.WebPart
          {
             //Label lblTitle;
             Label lblname=new Label();
            

          ///// the string info consumer from custom reciever   //
          ICommunicationInterface connectionInterface = null;

          // The consumer webpart  must define a method that
          // would accept the interface as an parameter
          // and must be decorated with ConnectionConsumer attribute     
          [ConnectionConsumer("Parameter1 Consumer",
                              "Parameter1 Consumer")]
          public void GetConnectionInterface(ICommunicationInterface
                                             _connectionInterface)
          {
              connectionInterface = _connectionInterface;
          }
          ///////////////////////////////////////////////////////// 

          public WP_Consumer()
          {
             
          }

              protected override void CreateChildControls()
              {
                  base.CreateChildControls();
                  
                  this.Controls.Add(lblname);
                 
              }


              protected override void OnPreRender(EventArgs e)
              {
                  base.OnPreRender(e);

                  if (connectionInterface != null)
                  {
                      lblname.Text = connectionInterface.parameter1 +
                      " is recieved!";
                     

                   }
                  else
                  {
                      lblname.Text = "nothing is recieved!";
                  }
                 
              }

           
                
           }

             

        }
      }

      After completing the code, compile and add the DLL in the Global Assembly Cache. (C:\Windows\Assembly)
      Create the corresponding ‘dwp’ file and add the SafeControl in the web.config of SharePoint Site.

      SharePoint - Cannot convert a primitive value to the expected type 'Edm.Double'. See the inner exception for more details If y...

      Ad