January 2009 Entries

I moved my blog from live spaces to a google sponsored blogger, ad the hits on the old site are going up, while the new hits here are low, does google promote live spaces more than blogger/blogspot? One more thing, I have been wondering. Tinyurl, etc. Use an outside service to delink things such as tweets. I wonder is this is affecting page rank from google. More page link in, more page rank, but do the shortened Url's still count for pagerank?

I saw a tweet from @andrewconnell about this, and he posted (Original Post) and I totally agree, this has been talked about for a while, and several MVP’s mentioned it, and said we would see it soon, a long time later we finally have it.

Basically, the rules for SP objects that are not automatically disposed are wrapped into a tool, to run against your code, and make sure you have no memory leaks.

Go get it here: http://code.msdn.microsoft.com/SPDisposeCheck

This is the first in a series of how-to posts on using SP standard controls in your own webpart or user controls.

I saw this post on MSDN forums, so I thought I would go ahead and answer.

Ask any developer that has been writing code for more than a year, and you will find that you should have reusable code. In .Net classes this mean either common classes, interfaces, or utility classes.

So pick one(or a couple), and use it.

My point being, instead of just showing how to use a PeopleEditor control, create a class that provides these methods, or a utility class.

Okay, enough banter, let’s get started.

You will eventually want to save the data into a SPList, or fill the control with data from a SPList into the control.  Even if you just want the values, extend your methods.  bleow are two methods I commonly use: (This method will also add the user to the Site Collection Users collection as SharePoint does OOB with people editor controls.)

/// <summary>
        /// Gets the value (Either SPUser or empty string) from the Control, can be used to store this directly to a SPListItem field.
        /// </summary>
        /// <param name="peopleEditorControl">The people editor control.</param>
        /// <returns>SPUser if found, or Empty String.</returns>
        public object GetPeopleEditorValue(PeopleEditor peopleEditorControl)
        {
            if (peopleEditorControl.IsValid)
            {
                try
                {
                    //Check to make sure that there is at least one user
                    if (peopleEditorControl.Accounts.Count > 0)
                    {
                        //For more than one user, this can be changed to a foreach.
                        PickerEntity entity = peopleEditorControl.Entities[0] as PickerEntity;
                        Hashtable peopleEditorData = entity.EntityData;

                        string strUserLogin = entity.Key;
                        string strUserEmail = peopleEditorData["Email"].ToString();
                        string strUserDisplayName = peopleEditorData["DisplayName"].ToString();

                        SPUser SelectedUser = null;
                        try
                        {
                            if (peopleEditorData.Contains("SPUserID") && (!String.IsNullOrEmpty(peopleEditorData["SPUserID"].ToString())))
                            {
                                SelectedUser = SPContext.Current.Web.SiteUsers.GetByID(Convert.ToInt16(Convert.ToString(peopleEditorData["SPUserID"])));
                            }
                            else
                            {
                                SelectedUser = SPContext.Current.Web.SiteUsers.GetByEmail(strUserEmail);
                            }
                        }
                        catch (Exception)
                        {
                            //To add the user to the site collection
                            SPSecurity.RunWithElevatedPrivileges(
                             delegate()
                             {
                                 //Could not find the user, add them to the site users.
                                 SPContext.Current.Web.SiteUsers.Add(strUserLogin, strUserEmail, strUserDisplayName, "");
                                 SelectedUser = SPContext.Current.Web.SiteUsers.GetByEmail(strUserEmail);
                             });
                        }

                        return SelectedUser;
                    }
                    else
                    {
                        return String.Empty;
                    }
                }
                catch (Exception ex)
                {
                    Debug.WriteLine("There was an error processing the PeopleEditor Control: " + ex.Message);
                    return String.Empty;
                }
            }
            else
            {
                //control is not valid, entries are not valid.
                //Throwing an exception is optional
                throw new Exception("People Editor Control is not valid, please correct the selection, and try again.");
            }
        }

Now, to set the value of a PeopleEditor control from list data:

/// <summary>
        /// Fills the control with the appropriate user, can be used to fill a control from a SPListItem field.
        /// </summary>
        /// <param name="strUserId">The user id. eg. id#;domain\login</param>
        /// <param name="peopleEditorControl">The people editor control.</param>
        public void FillPeopleEditorControl(string strUserId, PeopleEditor peopleEditorControl)
        {
            try
            {
                if (!String.IsNullOrEmpty(strUserId))
                {
                    strUserId = strUserId.Substring(0, strUserId.IndexOf(";"));
                    SPUser SelectedUser = SPContext.Current.Web.AllUsers.GetByID(Convert.ToInt16(strUserId));

                    PickerEntity pe = new PickerEntity();
                    pe.Key = SelectedUser.LoginName;
                    pe = peopleEditorControl.ValidateEntity(pe);

                    peopleEditorControl.Entities.Add(pe);
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine("There was an error loading the PeopleEditor control: " + ex.Message);
            }
        } 

Generally in the CreateChildControls override, I use Setup methods similar to the following:

/// <summary>
        /// Setup a people editor control.
        /// This method should be called from CreateChildControls method, and the control should be a member variable of the class.
        /// </summary>
        /// <param name="control">The control.</param>
        /// <param name="strControlId">The STR control id.</param>
        private void SetupPeopleEditorControl(ref PeopleEditor control, string strControlId)
        {
            //Create an instance of the control.
            control = new PeopleEditor();
            //Setup the ID
            control.ID = "pplEditor_" + strControlId;
            //This can be changed, or overriden as needed.
            control.Width = Unit.Pixel(200);
            //Only want one row, if using multipe users, then raise this number
            control.Rows = 1;
            //Set this to false to require an etnry
            control.AllowEmpty = true;
            //Set this to true to allow more than one selection
            control.MultiSelect = false;
            //Set this to the appropriate number of users
            control.MaximumEntities = 1;

            //Now add the control to the Controls collection.
            Controls.Add(control);
        }

Now there are a ton of ways to modify and extend the above methods, but they are a good stating point.

Hope this helps to explain some things about the People Editor Control.  Next post will be about the DateTimeControl!

Free Webinar sponsored by Colligo, so it will be a little bit of a sales pitch, but should also have some good content.

7 Ways To Get More From Your SharePoint Deployment Now

THURSDAY - February 19, 2009
8:00 AM PST
11:00 AM EST
4:00 PM London
5:00 PM Paris

You can register for free here

If you plan to use the laptop keyboard on say a Dell D620 for instance… Make sure you have numlock turned on in the bios, OR you have to turn it on EACH time you enter the VM, or should I say turn it OFF? Either way, trying to type/even login while holding down the FN key to get letters instead of numbers is quite frustrating.  Luckily, there are people out there that are experts in Virtual PC.  I found this blog post, that answered my questions right away.  Pretty short and to the point.

Link

Thanks!

So, about 2 weeks ago, VSeWSS 1.3 CTP was released.

All the facts are here.  So I thought I would give it a shot again, I had basically abandoned the 1.2 version, due to restrictions.  Now some of these things have been fixed, but not all of them.  I think… well, I will continue to use the Solution Generator to create List definitions, etc. that I put into my own projects.  One big problem still, you have to run it on a machine with SP on it.  I like to develop on my host OS, and depending on where I am, do not always have the 2GB extra memory to run a VM with VS 2008 on it.

Anyways, I would recommend that you take a look at it again, several things have gotten a lot nicer.

Still in the process of moving items from my old site, and checking out all of the tools/apps that can be used with blogger. So far so good!
After having some issues with posts and tracking, I decided to move it to a more used service.

I will be porting content and posts over the next week, and hopefully can be more consistent with a posting schedule here.

I was asked to update a SPD workflow, a long approval process, and the change was to modify the date AND time of an approval instead of just a Date.

First off, make sure your column supports date and time

AddingDateTimeColumn

Now, open up SPD, and connect to your site where the workflows are located. In the left pane, there should be a workflows section, and by expanding the workflow you wish to edit, the main window should look like this. (If you are creating a new WF, then you will skip this view, and be on the next view.)

Workflow1Objects

We are going to open the .xoml file. Getting us to the edit window for the workflow.

AddingConditions

I now am going to add a simple action to show how we can get Date AND Time stored into our column named DateApproved.

First, Click on Actions, and select "Update List Item", if it is not in the immediate list, Select "More Actions..." and by filtering to "List Actions" you can see "Update List Item".

WorkflowActions

Now, after we have added the Update List Item action, you should have an Action entry, with a bue link to "this list". By clicking on the link, you will get a window "Update List Item"

UpdateListItem

Click on Add... Selecting DateApproved

ValueAssignment

Next, by pressing "..." you will have the chance to put in the current date.

TodayAssignment

Click Ok, and now you have the Update ready. Click Ok.

UpdateListItemToday

Now let me explain a little about what is going on in the last steps.

Generally, using several "Set" actions you will be setting values on list entries, but the Update will perform an update immediately instead of when the Activity is finished.

So, now we can set our field value

AfterUpdateAction

Now, Click on Actions, and select "Set Field in Current Item". Again, if this is not in your list, you can find is from the same process above.

AddedSetFieldValueAction

Select "field" and choose, "DateApproved" (Or your own DateTime column)

AddingConditions2

Now clicking on "value" results in an option to choose Today or a function. This time, we want the function. (Fx)

AddingConditions3

Now, select the source item, (Current Item is what we just updated in the previous step)
And select "Modified" as the Field.

ValueAssignmentModified

Modified is the SharePoint internal date/time stored when the item was ... yeah "last modified".

Click Ok.

And Finally!

AddingConditionsFinal

There you have it. We updated the list item saving the "Today" date into a datetime field, then set the save field to "Modified" to get our time saved as well.

Hope this helps.

Saw this come up, and thought I would at least blog a link to a KB download and possible fix for some users.

http://www.microsoft.com/downloads/details.aspx?FamilyId=17C36612-632E-4C04-9382-987622ED1D64&displaylang=en

Today I started working for Slalom Consulting in the Atlanta office, they have a great crew.  After lunch I went to my first client, AT&T and by the looks of it, I will be there a while.  Simple customizations, and they are taking an agile approach, wanting to see some progress each week.  It will be a nice change to have something iterative again.  Looks like they need a couple workflows and some custom lists to feed some reporting information.  Hopefully it will be a fun project.

I have loaded Windows 7 on my laptop, and wanted to play with the new loading from a VHD... so I thought I would explain what I did.

On "My Computer" click on manage.

Select Disk Management.

On the right hand side, click on more actions and Create VHD

Now you have to wait some time for the disk to be created.  I would definitely suggest fixed size, as dynamic has never run well for me on Virtual PC in the past.

It will use 24GB of space in my example, so make sure you have some free space.  I would not create an image for less than 24GB with windows server 2003 R2, as I have experienced in the past, that this will fill up much faster than you expect.

After the VHD is finished, I open up Virtual PC 2007, create a new virtual machine, and use the existing VHD.  Capture your windows 2008 server ISO after the machine starts up, and reboot as needed, and should go into setup.  Install your OS.  From a little reading, I think the only other OS's that support VHD booting are Windows 7 and Windows Server 2008.  I tried the above with Win2k3, but could not boot it.  So, on to test win2k8 instead.

When I have some more time, I will finish up on this post.

So have you used symbols?  Of course you have, but do you know how you are using them?  Generally when a project is built in Visual Studio, a pdb file is generated, allowing you to debug the dll catching your break points etc.  So as long as you are debugging locally you are fine.  What happens in a case where, SharePoint for instance, you are remotely debugging? I mean using remote debugger to attach to processes on a remote server?  You will see that you can attach to the process w3wp.exe no problem, but then what, no symbols are found right?  So the code runs and you never hit the breakpoints that you expected to. 

And thus, you are stuck... either writing out debug statements, logging events in the eventlog, or writing text out to the screen... boo!  We are not in 1995 anymore or even 2000, and should not be using text to write out variable status along the way.  We want to see execution flow, and with a symbol server you can!

I heard a brodcast about this on Channel 9, but there was not great detail about it, so I went on investigating.

Here are my steps.

(I am going to highlight some things, as they are outside of the scope of this post... I know I hate it too.)

  1. Make sure you have remote debugging installed:
    Basically there is a remote debugging install from the VS CD/DVD just run it on the server and if you get stuck google it.
  2. Create a Symbol Share on your network:
    On a local server in your network (not your dev box) - I created a share on my sql box here, \\sql\symbols and gave all domain users read and myself read/write. I never though setting up a symbol server would be sooo easy :) Okay this is a good start for your local development, but make sure if you are a professional services developer, that there is a public place for your symbols, so you can debug at a client site!
  3. On all of my projects, I add a post build step:
    copy $(TargetDir)$(TargetName).pdb \\sql\symbols
    VSPostBuildStep
  4. Setup your debugging in VS (2008 in my case):
    In the Tools menu, select Options.
    Under Debugging, click on Symbols.
    Click on the folder icon, and add your path (\\sql\symbols in my case)
    VSDebuggingOptions

  5. You might also like to check the Cache symbols locally to a directory, to speed things up. (on our intranet, there is no need)
  6. Start debugging, connect to the remote machine, and watch the breakpoints go red again, and enjoy real remote debugging. (Even over the Internet)

I found some useful information from this MSDN Article, but all of the links in the group were not TOO helpful, but anyways, there you have it.  Remote debugging for SharePoint development, means that you no longer need to be on the server, or have a ton of RAM in your machine to run a VPC/VMWare machine...

-Later