tags:

views:

1104

answers:

5

I'm working on customizing a SharePoint document library called "Quality Documents" so that when new docs are added to the library, a random and unique number is generated and applied to a field named "Document Number". I coded the feature below, but it's not working. Can anyone see what might be the problem? Nothing happens, no errors nothing, the page just works fine, but no Document Number gets generated. Any suggestions?

using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.SharePoint;
using Microsoft.Office.Server;
using Microsoft.Office.Server.UserProfiles;

namespace QualityDocHandler
{
    class DocumentHandler : SPItemEventReceiver
    {
    /// <summary>
    /// Generates a random string with the given length
    /// </summary>
    /// <param name="size">Size of the string</param>
    /// <returns>Random string</returns>

    private string RandomString(int size)
    {
        StringBuilder builder = new StringBuilder();
        Random random = new Random();
        char ch;
        for (int i = 0; i < size; i++)
        {
            ch = Convert.ToChar(Convert.ToInt32(Math.Floor(26 * random.NextDouble() + 65)));
            builder.Append(ch);
        }
        return builder.ToString();
    }

    private string createDocNum(SPItemEventProperties properties)
    {
        int newRnd = 0;

        do
        {
            // set static department
            string dept = "QUA";

            // set date without separators
            string dateString = DateTime.Today.ToString("ddMMyyyy");

            // get 1st random string 
            string Rand1 = RandomString(4);

            // get 1st random string 
            string Rand2 = RandomString(4);

            // creat full document number
            string docNum = dept + "-" + dateString + "-" + Rand1 + "-" + Rand2;

            using (SPWeb oWeb = new SPSite(properties.SiteId).OpenWeb(properties.RelativeWebUrl))
            {
                SPList oList = oWeb.Lists["Quality Documents"];

                //create query
                SPQuery oQuery = new SPQuery();

                //configure the query  //
                oQuery.Query = "<Where><Eq><FieldRef Name='Document_x0020_Number' /><Value Type='Text'>" + docNum + "</Value></Eq></Where>";

                //get the collection of items in the list
                SPListItemCollection oItems = oList.GetItems(oQuery);

                if (oItems.Count > 0)
                {
                    newRnd = 0;
                }
                else
                {
                    newRnd = 1;
                }
            }
            return docNum;
        }
        while (newRnd < 1);

    }

    public override void ItemAdded(SPItemEventProperties properties)
    {
        base.ItemAdded(properties);
    }

    public override void ItemAdding(SPItemEventProperties properties)
    {

        string documentNum = createDocNum(properties);
        using (SPWeb oWeb = new SPSite(properties.SiteId).OpenWeb(properties.RelativeWebUrl))
        {
            SPListItem listItem = properties.ListItem;
            properties.AfterProperties["Document_x0020_Number"] = documentNum;
            listItem.Update();
            oWeb.Update();
        }
        base.ItemAdding(properties);

    }

    public override void ItemUpdated(SPItemEventProperties properties)
    {
        base.ItemUpdated(properties);
    }

    public override void ItemUpdating(SPItemEventProperties properties)
    {
        base.ItemUpdating(properties);
    }

}

}

A: 

listItem.Update(); probably throws a NullReferenceException, you can see the error message in the SharePoint log (or by attaching to w3wp), but errors from event receivers will not show up to the end user. They just cancel the event.

Besides, you don’t have to call Update on the list item or the web in ItemAdding. And when you’re creating a SPWeb for the current web in an event receiver you could use SPItemEventProperties.OpenWeb() instead. It saves you the "new SPSite()" call, which you actually forget to dispose in the above code. This could lead to problems if you’re having a medium to high load on your site. SPDisposeCheck is a good tool which could be used to find such issues.

JMD
+1  A: 

A few things:

  • You don't need to get a reference to listItem and use listItem.Update(). Just setting the AfterProperties should be enough.

  • Prevent the same event from firing multiple times by wrapping your ItemAdding method code with:

this.DisableEventFiring();
try
{
    // ...
}
finally
{
    this.EnableEventFiring();
}
  • Run SPDisposeCheck over your code. You might have a memory leak on the SPSite object with new SPSite().OpenWeb().

  • Have a read of Workarounds for ItemAdding/ItemAdded Event Handlers. I've never had to do this but using the display name instead of internal name may fix the problem.

  • In case of desperation, use ItemAdded() instead. Get a full reference to the original item and update that.

Alex Angas
Okay, it looks like both answers are suggesting that I don't need listitem.update, so I have removed that along with the SPSite block. Still not working though. I looked at the share point logs and see this message: "Failed to determine definition for Feature with ID"Here's what my ItemAdding event looks like now:public override void ItemAdding(SPItemEventProperties properties) { string documentNum = createDocNum(properties); properties.AfterProperties["Document_x0020_Number"] = documentNum; base.ItemAdding(properties); }
PushCode
FYI I just confirmed that the message I'm seeing in the logs isn't refering to the ID for this feature.
PushCode
A: 

Here's my latest code, still isn't working! :-(

using System; using System.Collections.Generic; using System.Text; using Microsoft.SharePoint; using Microsoft.Office.Server; using Microsoft.Office.Server.UserProfiles;

namespace QualityDocHandler
{
    class DocumentHandler : SPItemEventReceiver
    {

        /// <summary>
        /// Generates a random string with the given length
        /// </summary>
        /// <param name="size">Size of the string</param>
        /// <returns>Random string</returns>

        private string RandomString(int size)
        {
            StringBuilder builder = new StringBuilder();
            Random random = new Random();
            char ch;
            for (int i = 0; i < size; i++)
            {
                ch = Convert.ToChar(Convert.ToInt32(Math.Floor(26 * random.NextDouble() + 65)));
                builder.Append(ch);
            }
            return builder.ToString();
        }

        private string createDocNum(SPItemEventProperties properties)
        {
            int newRnd = 0;

            do
            {
                // set static department
                string dept = "QUA";

                // set date without separators
                string dateString = DateTime.Today.ToString("ddMMyyyy");

                // get 1st random string 
                string Rand1 = RandomString(4);

                // get 1st random string 
                string Rand2 = RandomString(4);

                // creat full document number
                string docNum = dept + "-" + dateString + "-" + Rand1 + "-" + Rand2;

                using (SPWeb oWeb = new SPSite(properties.SiteId).OpenWeb(properties.RelativeWebUrl))
                {
                    SPList oList = oWeb.Lists["Quality Documents"];

                    //create query
                    SPQuery oQuery = new SPQuery();

                    //configure the query  //
                    oQuery.Query = "<Where><Eq><FieldRef Name='Document_x0020_Number' /><Value Type='Text'>" + docNum + "</Value></Eq></Where>";

                    //get the collection of items in the list
                    SPListItemCollection oItems = oList.GetItems(oQuery);

                    if (oItems.Count > 0)
                    {
                        newRnd = 0;
                    }
                    else
                    {
                        newRnd = 1;
                    }
                }
                return docNum;
            }
            while (newRnd < 1);

        }

        public override void ItemAdded(SPItemEventProperties properties)
        {
            base.ItemAdded(properties);
            properties.ListItem["Document Number"] = properties.AfterProperties["Document Number"]; 
            properties.ListItem.SystemUpdate();
        }

        public override void ItemAdding(SPItemEventProperties properties)
        {
            this.DisableEventFiring();
            try
            {
                string documentNum = createDocNum(properties);
                properties.AfterProperties["Document Number"] = documentNum;
                base.ItemAdding(properties);
            }
            finally
            {
                this.EnableEventFiring();
            }
        }

        public override void ItemUpdated(SPItemEventProperties properties)
        {
            base.ItemUpdated(properties);
        }

        public override void ItemUpdating(SPItemEventProperties properties)
        {
            base.ItemUpdating(properties);
        }

    }
}
PushCode
A: 

I've reduced the code to just the bare minimum, manually setting a variable for document number, and I'm still not getting any result!!

Here's the latest code. What is going on!?

using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.SharePoint;
using Microsoft.Office.Server;
using Microsoft.Office.Server.UserProfiles;

namespace QualityDocHandler
{
    class DocumentHandler : SPItemEventReceiver
    {

        public override void ItemAdded(SPItemEventProperties properties)
        {
            base.ItemAdded(properties);
            properties.ListItem["Document_x0020_Number"] = properties.AfterProperties["Document_x0020_Number"]; 
            properties.ListItem.SystemUpdate();
        }

        public override void ItemAdding(SPItemEventProperties properties)
        {
            this.DisableEventFiring();
            try
            {
                string documentNum = "testNum1"; //createDocNum(properties);
                properties.AfterProperties["Document_x0020_Number"] = documentNum;
                base.ItemAdding(properties);
            }
            finally
            {
                this.EnableEventFiring();
            }
        }

        public override void ItemUpdated(SPItemEventProperties properties)
        {
            base.ItemUpdated(properties);
        }

        public override void ItemUpdating(SPItemEventProperties properties)
        {
            base.ItemUpdating(properties);
        }

    }
}
PushCode
A: 

I was able to get this working. Here's the finished code:

using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.SharePoint;
using Microsoft.Office.Server;
using Microsoft.Office.Server.UserProfiles;

namespace QualityDocHandler
{
    class DocumentHandler : SPItemEventReceiver
    {
        private readonly Random _rng = new Random();
        private const string _chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        private string RandomString(int size)
        { 
            char[] buffer = new char[size];
            for (int i = 0; i < size; i++)
            {
                buffer[i] = _chars[_rng.Next(_chars.Length)];
            }
            return new string(buffer);
        }

        private string createDocNum(SPItemEventProperties properties)
        {
            int newRnd = 0;

            do
            {
                // set static department
                string dept = "QUA";

                // set date without separators
                string dateString = DateTime.Today.ToString("ddMMyyyy");

                // get 1st random string 
                string Rand1 = RandomString(4);

                // get 2nd random string 
                string Rand2 = RandomString(4);

                // creat full document number
                string docNum = dept + "-" + dateString + "-" + Rand1 + "-" + Rand2;

                using (SPWeb oWeb = new SPSite(properties.SiteId).OpenWeb(properties.RelativeWebUrl))
                {
                    SPSiteDataQuery q = new SPSiteDataQuery();
                    q.Lists = "<Lists BaseType='1'/>";
                    q.Query = "<Where><Eq><FieldRef Name='Document_x0020_Number' /><Value Type='Text'>" + docNum + "</Value></Eq></Where>";
                    q.Webs = "<Webs Scope='SiteCollection' />";
                    q.RowLimit = 1;

                    System.Data.DataTable spSiteDataQueryResults = oWeb.GetSiteData(q);

                    if (spSiteDataQueryResults.Rows.Count > 0)
                    {
                        newRnd = 0;
                    }
                    else
                    {
                        newRnd = 1;
                    }
                }

                return docNum;
            }
            while (newRnd < 1);
        }

        public override void ItemAdded(SPItemEventProperties properties)
        {
            this.DisableEventFiring();
            properties.ListItem["Document Number"] = properties.AfterProperties["Document Number"];
            properties.ListItem.SystemUpdate();
            this.EnableEventFiring();
        }

        public override void ItemAdding(SPItemEventProperties properties)
        {
            string documentNum = createDocNum(properties);

            this.DisableEventFiring();
            properties.AfterProperties["Document Number"] = documentNum;
            this.EnableEventFiring();
        }

        public override void ItemUpdated(SPItemEventProperties properties)
        {
            base.ItemUpdated(properties);
        }

        public override void ItemUpdating(SPItemEventProperties properties)
        {
            base.ItemUpdating(properties);
        }
    }
}
PushCode