Skip to main content

Kristopher Baker

Go Search
Home
  

Tallahassee SPEED > Kristopher Baker
ItemAttachmentAdded
I have written an ItemAttachmentAdded event receiver. The business rule was that any attachment added to a list other than the document library had to be moved to the document library and a link to that moved file was to be placed in a field on the related list item so the partner could follow the link to the file in the document library. Having not found this information put together anywhere, I felt it was important to put this little tidbit of code out there. YMMV.

ItemAttachmentAdded, as its name implies, is an event that occurs when an attachment has been uploaded to a list with a list item. It is crucial to understand that when you have more than one attachment being added to a list item the server will run the uploading of these files in threads.

Let's say you are uploading 10 files on one list item. The uploading process may take 1, 2, 3, or more of the files at a time and upload them in a thread. The next ones will be added to other threads until all of the files have been copied into their folders under that list item. This caused me a headache because I could not debug the code. As I would step through the debugger I would find my current debugger line bouncing around to other spots because of the other threads hitting my breakpoints. At any given moment I could be brought back to the same variable but have different values in it each time.

I took a crash-course (i.e. the GOOG) on threads and found this handy little piece of code called "lock()." I am not a .NET wizard so I can't fully explain what it is doing but this is an old one: you have to give lock() an object. Apparently ANY object will do. As you can see from my code I just gave it a new object(). Lock apparently allows execution of one thread at a time. The other threads are queued up to run after the current thread is unlocked. In this way you can see from my code that I am running the work of appending the link to each file in a string builder, copying the file and then adding it to a list of files to delete from the current list item. After each run I can loop back and take in the next thread.

I added my code for debugging this monster in the catch statement. I actually removed all the other calls I had peppered throughout this code to examine each variable as I went through. I had about 20 calls to DebugIt(). That was what told me that the values were changing a WHOLE lot. For example, I could see that my attachments collection only had a few of my attachments in it. This was my first tip-off that I was dealing with threading...

I don't claim that this code is pretty. I don't claim that this code is refactored correctly. I don't claim that it is even a correct use of lock(). I can only claim that this bit of code now allows me to get all of my attachments into the document library and write a link back in the original item. (O;

using Microsoft.SharePoint;
using Constants;
using System.Collections.Generic;
using System.Text;
using System;
using System.Diagnostics;

namespace Intake_Handler
{
    class Attachments_Handler : SPItemEventReceiver
    {
        static readonly object _object = new object();
        public override void ItemAttachmentAdded(SPItemEventProperties properties)
        {
            lock (_object)
            {
                using (SPWeb web = properties.ListItem.Web)
                {
                    try
                    {
                        this.DisableEventFiring();
                        base.ItemAttachmentAdded(properties);

                        SPList docLib = web.Lists[ListNames.CASE_DOCUMENTS];
                        SPFolder rootFolder = docLib.RootFolder;
                        string docLibURL = web.Url + "/" + rootFolder.ToString();
                        SPListItem item = properties.ListItem;
                        SPAttachmentCollection attachments = item.Attachments;
                        List<string> filesToDelete = new List<string>();
                        StringBuilder sb = new StringBuilder();
                        var attachmentLink = item["AttachmentLink"] == null ? string.Empty : item["AttachmentLink"].ToString();
                        sb.Append(attachmentLink);
                  
                        if (attachments.Count != 0)
                        {
                            foreach (string fileName in attachments)
                            {
                                SPFile file = item.ParentList.ParentWeb.GetFile(item.Attachments.UrlPrefix + fileName);
                                byte[] fileBytes = new byte[0];
                                fileBytes = file.OpenBinary();
                                string destURL = rootFolder.Url + "/" + file.Name;
                                SPFile destFile = rootFolder.Files.Add(destURL, fileBytes, true);
                                sb.Append(docLibURL + "/" + fileName + " | ");
                  
                                filesToDelete.Add(fileName);
                            }
                        }

                        item["AttachmentLink"] = sb.ToString();

                        foreach (string fileToDelete in filesToDelete)
                        {
                            attachments.Delete(fileToDelete);
                        }

                        item.SystemUpdate();
                    }

                    catch (Exception ex)
                    {
                        DebugIt(web, string.Format("Catch: {0}", ex.ToString()));
                    }
                    finally
                    {
                        this.EnableEventFiring();
                    }
                }
            }
        }
        public static void DebugIt(SPWeb web, string body)
        {
            SPList list = web.Lists["debug"];
            SPListItem item = list.Items.Add();
            item[SPBuiltInFieldId.Title] = DateTime.Now.Millisecond.ToString();
            item["body"] = body;
            item.Update();
        }
    }
}

New Web Log!
Thank you Jamey for setting me up here!

I hope to be able to find enough time to make this web log useful to myself, as well as others. This will be my first 'official' web log. I say official because I dabbled in keeping a sort of diary/web log a long while back on LiveJournal while I was still "finding myself." With that account now buried deeply into the past I feel the time is right to begin sharing some of the bits and pieces of knowledge that I have learned. Particularly, I am excited about what I am learning about SharePoint.

I work for a consultant company named SkillStorm, Inc. that contracts with the Florida Department of Transportation here in Tallahassee. I have been working directly with Windows SharePoint Services 3.0 for a little more than three years. In that time I have converted static web sites to SharePoint sites, converted Lotus Notes applications into SharePoint Designer 2007 (SPD) applications utilizing workflows built with SPD, built event handlers in Visual Studio 2008 (VS2008), incorporated jQuery into almost every project I work on and have begun to dabble in building custom content types, VS2008 workflows and custom column types.

I am looking forward to working with some of the brilliant minds that are working with SharePoint from our user group as well as the surrounding areas. While my interest lies mostly in the development side of the house I find myself continually fascinated by the ease with which SharePoint users are able to take on the responsibility of serving their own content. SharePoint has been a joy to work with and the investment that any company makes in this exciting technology is going to do wonders for them.

Here's to a great year for SharePoint and for TallahasseeSpeed.com!

-kb

 ‭(Hidden)‬ Content Editor Web Part

 ‭(Hidden)‬ Admin Links