Managing Work E-mail with a ‘go-to’ folder

In today’s connected world, do you find disconnecting from work email is near impossible on weekends? Do you ever find yourself involved in personal activity, only to receive an email from a client who is catching up on their email? Do you receive work email on your personal smart phone, perhaps along with your personal email? Are you unable to stop responding to work email in your personal time?

If you answered ‘yes’ to any of the above questions then you might have asked yourself if there is a better way to manage work email polluting your personal time.

Before I explain how I went about configuring my work-email and cell phone, I want to point out that I am not suggesting that I wish to avoid work email outside office hours – that would be a near impossibility in my line of work – just that I want better control of when I am interrupted. I got my idea from watching my fiancé, who has a separate blackberry for work to personal – she is able to put down her work blackberry in the evening and “choose” when to pick it up. If there is an emergency in the office, someone will call her work phone and she can address the issue. Only having one smart phone and numerous laptop computers, I wanted to replicate the ability to “put down” the office at specific points of my evening or weekend, without disconnecting completely.

Enter Microsoft Exchange Rules…

The following configuration assumes you are using Microsoft Office and Exchange Server at the office. You can achieve similar results with G-mail and other email services, as long as you can configure server-side rules to manage email.

(Note: I use Outlook 2010, which the screenshots show, but older versions of Outlook typically offer similar functionality).

Create a folder under your inbox to house work email – I called mine @@Client because I still want internal office email to stay in my inbox.

From the Outlook Home tab, click on the Rules icon in the Move section, and select Create Rule

Click the Advanced Options button on the Create Rule dialog

Choose the option “with specific words in the sender’s email address,” click the underlined “specific words” and add “@”

image

Click the next button and then choose the following actions:

– stop processing more rules

– move it to a specified folder

Click the link “specified folder” and choose the folder, under your Inbox, that you created earlier

image

Click the Next button, and then choose the following exceptions:

– except if it is a meeting invitation or update

– except if it is marked as High Importance

image

Click the Next button, and then give the rule a name, finally click the Finish button

What happens now?

The rule you just created is an Exchange Server-side rule, which means Exchange will process it whether Outlook is running or not. This is important – you do not want to receive email on your cell phone when Outlook is not up and running on your work computer.

If not already configured, make sure that your smart phone shows you the main Inbox folder only for your work account. I have an iPhone and the default “All Accounts” folder shows only email in my main inboxes. If I want to read client specific emails I now have to go and look for the @@client folder under my work account – which is the point!

Working with this new setup does require a certain amount of diligence. If you so desire, there is nothing stopping you ignoring all client email for a period, which will likely hurt you in the short term when next in a meeting and your client asks whether you read their emails. The main point of this configuration is to allow you greater control of when and how you access emails, without technology interrupting you at inopportune moments. As a rule, I check my client folder at least twice a day when in the office working, and during downtimes in the weekend/evenings.

Synchronous Web Events

Triggering custom behavior, after sub-site (web) creation in SharePoint 2007, involved stapling a custom site feature to the site definition. SharePoint 2010 provides additional “web” events, which developers may bind custom event receivers and execute custom code.

Creating a new event receiver and binding to web events is a simple exercise in Visual Studio 2010 (Add a new event receiver item to a SharePoint project and specify the event).

I recently wrote a custom event receiver to provision content types in the Pages library of a publishing site at site creation – straight forward enough.  Everything worked great inside the debugger, but after deployment, SharePoint would kick back a synchronization error, indicating a previous update had been made, during the provisioning process.

After some head scratching, I suspected that even though SharePoint fired the WebProvisioned event, the site provisioning process was continuing in the background. A breakpoint set on my catch block tipped me off because the pages library did not exist.

I consulted with a colleague, who made me aware of the following XML node in the event receiver Elements.xml file:

<Synchronization>Synchronous</Synchronization>

By default, SharePoint calls the WebProvisioned event asynchronously, without the above node in the Elements.xml file.

After a quick recompile and deployment (with the above node added), I was able to test sub-site provisioning working and my event receiver running each time without failure.

How to change a Page Layout Associated Content Type Id Programmatically

I developed some code that uploads a new page layout file (ASPX) from disk to the Master Page Gallery of a site collection.  I wanted to associate the uploaded publishing page with an existing content type, such as the “Welcome Page” content type.  This is equivalent to editing the properties of the page layout and setting the “Associated Content Type” property…

 

image

 

Setting the Associated Content Type property in code is not as easy as thought.  After trawling around the web for an hour, I found no good example.  I found plenty of examples to create a Page Layout declaratively in XML and assign the associated content property, but no examples in C# for an existing SPFile object.  Then it hit me…

The PublishingAssociatedContentType property expects a formatted string that contains both the display name and the content type ID.  So, armed with both an SPFile object that is the page layout file and an SPContentType object, I was able to associate the page layout with the following code:

file.Item.Properties["PublishingAssociatedContentType"] = String.Format(";#{0};#{1};#", spCT.Name, spCT.Id.ToString());

Make sure to call file.Item.Update();

Wham!

Assigning a Unique Master Page to a Page Layout in SharePoint 2010

In the old days of SharePoint 2007, the master page reference in a publishing page layout lived in the MasterPageFile attribute of the @Page reference at the top off the layout file. 

This made good when you needed to create a page layout that stood out from the common branding of the site – such as a page layout that had no chrome for popups etc… and this was exactly what I wanted to accomplish today in SharePoint 2010.

Unfortunately, Microsoft changed the way in which Page Layouts associate with their master page.  Open any of the out of the box page layouts in SP2010 and you should notice that there are no references to master page files anywhere.  This is because the master page association is handled by the containing site settings.

So how does one go about creating a “special” page layout that does not follow the same branding as the rest of the site?  One option is to isolate such pages in sub sites, which is frankly crappy.  Unfortunately, the alternative is much better – the general consensus is that the solution to this problem consists of creating a new sub class that inherits the PublishingLayoutPage class and sets the CustomMasterUrl property explicitly in the Page Init event.

Thanks to Eric for his post, which I referenced to solve this issue.

TaxonomyClientService.AddTerms Wrong Documentation

I’ve been working lately on a project that requires access to the Managed Metadata Service in SP2010.  I got to a point where I needed to add a term to the default term store under a term set.

I have some code in my project that takes in the following parameters and creates a term in the term store:

– TaxonomyClientService proxy instance

– Term name

– Term store ID

– Term Set ID

I needed to use the AddTerm method of the proxy to create a new term, and spent most of my afternoon wrestling with the format of the NewTerms parameter of the method.

The following MSDN documentation is wrong! (here) – or at least not informative.

The MSDN documentation stipulates to use NewTerm nodes to wrap new terms in the XML passed to the service.  What the documentation did not tell me was:

1. The term set must be open, otherwise the method returns an empty string.

2. The method need the exact syntax for the XML to work – looking on the web, I found no real answer to this problem, and ended up reflecting the web service code to get my answer.  Below is a sample piece of XML.

<newTerms><newTerm label="MyTerm" clientId="1" parentTermId="GUID of parent or empty GUID if none"></newTerm></newTerms>

Worth noting with the above XML…

1. Notice the lowercase use of newTerms and newTerm (not uppercase N as in the MSDN documentation)

2. clientId does very little and so you can pass the value 1

3. The parentTermId must be a real GUID, and Guid.Empty if no parent

4. New terms wrap in the newTerms node, which MSDN failed to mention.

I hope this post saves others an afternoon worth of work, which it cost me.

Programmatically Provision Term Store

I recently had to write a feature to provision the SharePoint 2010 Term Store. Numerous blog posts exist on how to populate the term store using Power Shell or how to write XML to add terms to the store, but what I wanted to do was a little different.  The requirements for my feature were as follows:

1. Works in SharePoint 2010 (duh)

2. Create a new Term Store Group in default Term Store

3. Great a series of Term Sets

4. Create a series of Terms in the Term Sets

5. Deploy the feature at the Farm scope.

One of the issues with setting up a Term Store in the SharePoint 2010 Metadata Managed Service Application is that the service can be temperamental if the proxy for the service does not have the setting checked for default term store storage location for site collections.  I wrote a previous blog post on this issue here

To save you some reading, the issue above is with obtaining the default term store instance for a given site collection when using the TaxonomySession object in the Microsoft.SharePoint.Taxonomy API.  As my previous post mentioned, the way to resolve this issue is to check the option under Properties fore the proxy and ensure that the current user had full control as an Administrator of the Managed Metadata Service Application.

Nice one Rob! But what if you want to avoid the manual step and want to configure these operations in code?  It is not as hard as it may sound, check out the code below…

        private void ProvisionMetadataService()
        {
            // We don't have the metadata service configured, so let's do that.
            var proxy = SPFarm.Local.ServiceProxies.Where(s =&gt; s.GetType().Name.Equals
(&quot;MetadataWebServiceProxy&quot;)).FirstOrDefault();
            if (null == proxy) 
throw new SPException(&quot;Failed to get instance of metadata web service proxy, is it installed?&quot;);
            foreach (var proxyApp in proxy.ApplicationProxies.Where(proxyApp =&gt; 
proxyApp.Properties.ContainsKey(&quot;IsDefaultSiteCollectionTaxonomy&quot;)))
            {
                proxyApp.Properties[&quot;IsDefaultSiteCollectionTaxonomy&quot;] = true;
                proxyApp.Update(true);
            }
            // Give the current user access rights to the metadata service.
            var service = SPFarm.Local.Services.Where(s =&gt; s.GetType().Name.Equals
(&quot;MetadataWebService&quot;)).FirstOrDefault();
            if (null == service) 
throw new SPException(&quot;Failed to get instance of metadata web service, is it installed?&quot;);
            var serviceApp = service.Applications.OfType&lt;SPIisWebServiceApplication&gt;().FirstOrDefault();
            if (null == serviceApp) 
throw new SPException(&quot;Failed to get instance of metadata web service app, is it installed?&quot;);
            var security = serviceApp.GetAdministrationAccessControl();
            var cba = SPClaimProviderManager.Local;
            var claim = cba.ConvertIdentifierToClaim(&quot;DOMAINuser&quot;, 
SPIdentifierTypes.WindowsSamAccountName);
            security.AddAccessRule(
new SPAclAccessRule&lt;SPCentralAdministrationRights&gt;(claim, SPCentralAdministrationRights.FullControl));
            serviceApp.SetAdministrationAccessControl(security);
            serviceApp.Uncache();
            service.Uncache();
        }

 

With the above code executed, you can then open an instance of the site collection to the Central Admin Site and then request the default site collection term store with the following code:

using (var site = new SPSite(_farmUrl))
            {
                // Do we have explicit credentials?
                if (!String.IsNullOrEmpty(_username) &amp;&amp; !String.IsNullOrEmpty(_password))
                {
                    var user = site.RootWeb.AllUsers[_username];
                    if (null == user) 
throw new SPException(String.Format(&quot;no user in site collection {0}&quot;, _username));
                    using (var secureSite = new SPSite(site.ID, user.UserToken))
                    {
                        // Get the term store.
                        var session = new TaxonomySession(secureSite);
                        var termStore = session.DefaultSiteCollectionTermStore;
                        if (null == termStore) 
throw new SPException(&quot;Failed to get the default term store instance&quot;);
                        del(termStore);
                    }
                }
                else
                {
                    // Get the term store.
                    var session = new TaxonomySession(site);
                    var termStore = session.DefaultSiteCollectionTermStore;
                    if (null == termStore) 
throw new SPException(&quot;Failed to get the default term store instance&quot;);
                    del(termStore);
                }
            }

It’s not obvious from the code above, but the call to “del” is a delegate call that I include as a parameter to the wrapping method of the above cod.

So, lastly, how did I get the Central Admin URL in the feature receiver?  See below:

var app = SPAdministratrionWebApplication.GetInstanceLocalToFarm(SPFarm.Local);
var url = app.Sites[0].Url

Managed Metadata Service: DefaultSiteCollectionTermStore == null

I happened to configure my SP2010 farm using Powershell automated scripts and and as a result my default Metadata term store proxy was not default for any new or existing site collections.  This issue manifested itself when I was trying to access the default site collection term store via the SharePoint API as a property of the TaxonomySession class.

I came across the following blog post, which got me as far as establishing the metadata service proxy as default for site collection.  To access the DefaultSiteCollectionTermStore property I had to configure additional permissions.

By default my Metadata Service Applications allowed permitted access to the farm and application pool accounts, but my custom code was running under the context of the logged in user.  To rectify this issue I could either elevate permissions to run as the app pool user, or give the logged in user explicit permissions by clicking through as follows in Central Administration:

1. Central Administration

2. Application Management

3. Manage Service Applications

4. Metadata Service Application (not the proxy)

5. Permissions (Ribbon)

6. Add the user via the dialog and give them permissions to access the application.

Interview Questions for SharePoint Developer Position

See how you do…

Q1. Name two SharePoint API objects you should define to open a site collection and sub web.

Q2. What is the role of the Shared Services provider in Microsoft Office SharePoint Server 2007?

Q3. How man content databases can a site collection span?

Q4. Can a content database contain multiple site collections?

Q5. What SharePoint capability allows navigation access to multiple site collections in a single site collection?

Q6. What is STSADM?

Q7. What is a metadata property in the search configuration?

Q8. What SharePoint capability allows for the use of multiple domain names for the same SharePoint site application?

Q9. What is a SharePoint Feature and how are they deployed?

Q10. Name all 4 feature scope levels

Q11. Name two development approaches to creating a WSP (SharePoint Deployment Package)

Q12. Should you dispose an instance of SPWeb obtained from the ALLWEBS collection of an SPSite object?

Q13. Should you dispose the ROOTWEB object of an SPSite object?

Q14. Should you dispose the site or web objects referenced from SPCONTEXT?

Q15. Your site crashes and SharePoint reports a standard error message after installing some custom code, how would you diagnose the issue?

Q16. How would you apply a common branding to all pages on your publishing sites?

Q17. What feature do page layouts belong?

Q18. How many direct parent content types may a child content type have?

Q19. Comment on why explicit permissions given to list items is bad practice

Q20. Is “Contributors” a SharePoint Group or Permission Level?

Q21. What is the role of the term store?

Q22. Comment how SP2010 no longer uses the SSP, and the new approach to service architecture

Q23. What is the sandbox?

Q24. What is Claims-Based-Authentication?

Q25. What Microsoft Office application allows design and implementation of workflows visually?

2010 in review

The stats helper monkeys at WordPress.com mulled over how this blog did in 2010, and here’s a high level summary of its overall blog health:

Healthy blog!

The Blog-Health-o-Meter™ reads Fresher than ever.

Crunchy numbers

Featured image

The average container ship can carry about 4,500 containers. This blog was viewed about 24,000 times in 2010. If each view were a shipping container, your blog would have filled about 5 fully loaded ships.

In 2010, there were 4 new posts, growing the total archive of this blog to 314 posts. There were 4 pictures uploaded, taking up a total of 126kb.

The busiest day of the year was June 15th with 128 views. The most popular post that day was Efficient way to add a new item to a SharePoint list.

Where did they come from?

The top referring sites in 2010 were codeproject.com, stackoverflow.com, dotnetslackers.com, forums.asp.net, and dotnetmafia.com.

Some visitors came searching, mostly for .net wrapper for com elevation, robert garrett, rob garrett, spperformancemonitor, and the site collection could not be restored. if this problem persists please make.

Attractions in 2010

These are the posts and pages that got the most views in 2010.

1

Efficient way to add a new item to a SharePoint list February 2009
11 comments

2

Prolific PL-2303 Driver – Vista x64 February 2008
18 comments

3

SharePoint Development Best Practices (Summary) February 2009
7 comments

4

Reinstalling COM+ on Windows XP April 2005
48 comments

5

Configuring RBS for SP2010 January 2010
3 comments