2

I am a bit confused if i am breaking the sharepoint best practice inside my sharepoint 2013 event receiver. now i have the following general requirements:-

  • site collection url = http://servrname/kb/pmo
  • sub-site url = http://servername/kb/pmo/projects/
  • inside this sub-site i have a list named "projects". where i define an event receiver which will fire when the item is added. and the event receiver will create a sub-site under the projects. such as "http://servername/kb/pmo/projects/SubSiteA"

so i developed the following event receiver , which will run under RunWithElevatedPrivileges to allow non-full control users to be able to create subsites inside the event receiver:-

    public class EventReceiver1 : SPItemEventReceiver
    {
        /// <summary>
        /// An item is being added.
        /// </summary>

        public override void ItemAdded(SPItemEventProperties properties)
        {
               base.ItemAdded(properties);
    SPSecurity.RunWithElevatedPrivileges(delegate()
    {
       using (SPSite site = new SPSite(properties.SiteId))

       {

            string currenweburl = properties.RelativeWebUrl;

            using (SPWeb spCurrentSite = site.OpenWeb(currenweburl))
            {


                String curListName = properties.ListTitle;                       
                if (curListName.ToLower() == "projects")
                {

                    //Get the SPListItem object that raised the event

                    SPListItem curItem = properties.ListItem;

                    //Get the Title field from this item. This will be the name of our new subsite

                    String curItemSiteName = properties.AfterProperties["Title"].ToString();
                    String curItemID = properties.ListItemId.ToString();

                    //Get the Description field from this item. This will be the description for our new subsite

                    //string curItemDescription = properties.AfterProperties["Description"].ToString();

                    //Update the SiteUrl field of the item, this is the URL of our new subsite

                    //properties.AfterProperties["SiteUrl"] = spCurrentSite.Url + "/" + curItemSiteName;



                    // Get the rootweb where we will find the available templates

                    SPWeb rootWeb = spCurrentSite.Site.RootWeb;

                    //Get all the webtemplates available on this site collection

                    SPWebTemplateCollection webTemplates = rootWeb.GetAvailableWebTemplates(1033);

                    SPWebTemplate webTemplate = null;

                    String webTemplateName = "NewProject"; //this is the name of the template we will use

                    String webTemplateSearchName = "";


                    //Get the template based on name. In this example 'ProjectTemplate'

                    //Loop through the available templates
                    for (int i = 0; i < webTemplates.Count; i++)
                    {

                        webTemplateSearchName = webTemplates[i].Name.ToString();

                        //Compare to see if this is the 'ProjectTemplate' template
                        if (webTemplateSearchName.Contains(webTemplateName))
                        {
                            //when we have found the matching template,set webTemplate to the foundt template and exit the if loop
                            webTemplate = webTemplates[webTemplateSearchName];

                            break;

                        }

                    }

                    //Create the subsite based on the template from the Solution Gallery

                    SPWeb newSite = spCurrentSite.Webs.Add(curItemID, curItemSiteName, "created automatically after adding a new project item", Convert.ToUInt16(1033), webTemplate, false, false);

                    //Set the new subsite to inherit it's top navigation from the parent site, Use false if you do not want this.

                    newSite.Navigation.UseShared = true;
                    string masterPage = "Custom.master";
                    var masterUri = new Uri(rootWeb.Url + "/_catalogs/masterpage/" + masterPage);

                    newSite.MasterUrl = masterUri.AbsolutePath;

                    newSite.CustomMasterUrl = masterUri.AbsolutePath;
                    newSite.Update();
                    newSite.Close();





                }
            }
        }
   });
//
        }


    }
} 

now the above event receiver is working fine for me and i thought everything is well. but i read this article from MSDN link about the best practices inside event receivers and they mentioned that :-

Do not instantiate an SPWeb, SPSite, SPList, or SPListItem object within an event receiver.

which i am breaking since i am initiating the SPSite as follow:-

using (SPSite site = new SPSite(properties.SiteId))

but i am doing so because if i modify my code to use the following:-

 using (SPWeb spCurrentSite = properties.OpenWeb())

instead of relying on the SPSite as i am currently doing :-

 using (SPWeb spCurrentSite = site.OpenWeb(currenweburl))

then this will result in ignoring the RunWithElevatedPrivileges. because to get the effect of RunWithElevatedPrivileges,then the SPWeb need to be created from an instance of SPSite as mentioned on this link.. so can anyone adivce how i need to appraoch my above event receiver ? so now i am having the event receiver working well, but seems that i am breaking the best practice. now performance is not the best practice i am worry about the most,,, but the face that this might happen is what makes me worry Calls to the Update method on these instances can cause subsequent Update calls in other registered event receivers to fail.

so can anyone advice how to make my event receiver following the best practices ?

2

For creating sub sites in event receiver you would need to create new instance of SPweb via url because of RunWithElevatedPrivileges. Also your worry on below

Calls to the Update method on these instances can cause subsequent Update calls in other registered event receivers to fail.

This becomes valid when you are updating list item within event reciever by creating new instance of object. If you doing update on web and this web does not have any event receiver it should not cause any problem. Problem with updating object created by new instance within event receiver of same object is that another event receivers can fail.

  • so you mean in my above event receiver i will not face any issue, is this correct ? – john Gu Dec 6 '16 at 14:44
  • now let say inside my above event receiver, i want to update the item which has been added, and set its "SiteCreationStatus" column to be = "Sub Site Created" after the sub-site is created automatically ,, then how i should appraoch this inside my above code to make sure i will not be breaking the best practice ? if i write something such as SPListItem currentItem = properties.ListItem; currentItem["SiteCreationStatus"] = "Sub Site Created"; currentItem.SystemUpdate(); should this be fine ? – john Gu Dec 6 '16 at 14:51
  • 1
    Hi John, yes that is correct approach do it, if you are updating item, do it outside run with elevated privileges and do not create new SPweb object with url.... – Siddharth Vaghasia Dec 6 '16 at 15:44
  • 1
    that is what Microsoft is suggesting that performance will degrade and plus in other event receivers update call will fail..... – Siddharth Vaghasia Dec 7 '16 at 4:17
  • 1
    @john...this is correct...update you list item outside of runwithelevated privileges.... – Siddharth Vaghasia Dec 9 '16 at 6:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.