Syrinx on SharePoint

Syrinx SharePoint Team Blog
Need help on your project? info@syrinx.com, or toll free (888) 579-7469, press 1

News



Need help with your SharePoint project?

Syrinx works with clients throughout New England and across the United States to architect, design, develop, and deploy SharePoint implementations. Working on fully outsourced projects, as part of your team, helping to train your team, or rescuing projects in trouble, we are comfortable doing it all. Projects from a couple weeks to several months in duration, reference clients available. Contact us today - info@syrinx.com, or toll free (888) 579-7469 and press 1 to speak to someone now!

Twitter question

A recent question on Twitter:

 "[SharePoint] costs as much to buy/implement/run in money as the productivity loss of not having it - agree or disagree?"

I would say if you measure this in a vacuum, in the scope of one single project it's probably a wash (money out == savings). The real ROI starts showing up on projects 2 - 200 where you already have the infrastructure set up, people know how to use the platform, you've paid for the licensing, and now you are able to solve new challenges using SharePoint with little effort and cost. Your users start solving business needs themselves (or with just a little help) using doucment libraries, lists, etc. I think that is where the real 'wins' happen.

 

Posted: Feb 16 2010, 02:24 PM by AndrewG | with no comments
Filed under: , ,
SharePoint Server 2010 Initial Installation

I just wanted to drop a quick note about the installation of the SharePoint Server 2010 Beta released yesterday on MSDN.

I setup a new virtual machine in my Hyper-V server as a new dedicated 2010 Beta server.  I installed Office 2010 beta and SharePoint Designer 2010 with no issues whatsoever.  SharePoint Server provided to be a little less helpful.  It wouldn't be SharePoint if it didn't make me work for it!

I want to drop a quick warning in case you run into the 2 issues I had.

1.  The prerequisite installs kept failing because it was unable to install PowerShell V2.  This boils down to PowerShell V2 refusing to install if V1 exists (although this took a little digging below the surface), which is mysteriously installed on my vanilla Server 2008 Standard via a random KB / Windows Update.  Fine, except you can't find the specific KB to therefore uninstall it.  It turns out to be a piece of cake after running in circles.  Use the server manager "Features" to remove PowerShell V1 and voila, you should be all set.  The traditional methods for remove programs yielded no results.

2.  The SharePoint Configuration Wizard told me that my SQL Server was not up to date.  The warning made it sound like I needed SP1 for SQL 2008, which I had not installed.  I went ahead and got that completed and the error/warning persisted.  If you read carefully the message also mentions a specific KB which has a ton of hotfixes embedded within them.  I just downloaded both files referenced in the hotfixes from that KB and installed them.

In all I installed SP1 three times with the various KB bundles, but after that the installation went smooth.  My machine is now sitting at the Central Admin configuration screen while Visual Studio 2010 beta installs.

I will try to report back on any hiccups / issues with the CA configuration.  So far it's not too bad!

I hope this helps,

-Ryan

SPC 2009 Wrap-up

The last day of the SPC had some tech-laden sessions hosted by Andrew Connell. The first was about migrating from 2007 to 2010, and how you can add the nice 2010 development features (like the ribbon and the developer dashboard) back into your 2007 master pages when you migrate them. The theme seems to be that you invested in branding and customizing 2007, and Microsoft is making it straightforward to move that content to 2010. The idea is to not have to stop doing work in your 2007 instance waiting for 2010 to release. All in all, it looks like going from 2007 to 2010 should be much easier than 2003 to 2007.

Andrew’s second session was on the ability to create Service Applications. When I first heard it described (local versus proxy execution, service discovery, etc) I started having flashbacks to an app we built back in 1998 in C++ – the Bridge Pattern and CORBA live again! The more I heard the more I was impressed with what had been implemented. It is CORBA-like, but seems to be much easier to use/administer and much faster. Still some hand-rolling of code to bind things together, but all in all some powerful capability if you need it. Who might need it? I can see an ISV who wants to embed some of their product’s capabilities into SharePoint where there are long-running operations or a need for horizontal scalability of compute-intensive operations. There is a decent amount of development overhead to do so, but it’s nice to know the capability is there if needed. One Best Practice mentioned – if you do decide to create a Service Application, make sure to create the Central Admin and PowerShell interfaces to make administration straightforward.

The conference was a great time and was very informative. A few themes

  • I noticed a lot of people from other countries at the conference – SharePoint is definitely catching on worldwide and is standing up to the multi-lingual challenge.
  • Microsoft decided to build on the good ideas of Excel Services in 2007 and make it super easy and powerful to do basic BI in Excel Services 2010
  • The success of Excel Services in 2007 has borne Access Services and Visio Services in 2010. My instincts say that Access Services will be much more popular – making it much easier to take a departmental application and “upsize” it to the enterprise
  • The sheer size of the conference was an indicator of how huge the product has become, and how much customers and Microsoft are betting on the platform.

Our next steps will be to update our webinars to show some of the new 2010 features and how they relate to the existing features, and to try everything out in the Beta release next month. Looking forward to it!

Microsoft SharePoint 2010 (SharePoint Conference 2009)

First let me apologize for the lack of blogging for a while.  We have been under the gun with a sizable SharePoint development project.  I have gown farther down into the innards of InfoPath then I ever thought possible.  To give you an idea, we worked over 140 hours in the 2 weeks prior to the conference.  I promise to be better, and now I have good reason to do so:

We at Syrinx just got back from a long week loaded with sessions, booths, experts, and information all about SharePoint 2010.  All I can say is *WOW*.  I predict the trend of SharePoint adoption to continue to to climb at an alarming rate. 

I'm sure everyone is out there blogging about all the new features, and that's great!  I'm just going to run down the high-level features from the sessions I attended and information I gathered.  This is no way an exhaustive list, but as I dig into the new capabilities I will blog about them.

SharePoint Online / Sandbox Development and Testing

SharePoint 2010 will be offered in a software-as-a-service mode with WILL allow custom coding via a sandbox mode that runs in a protected state.

Business Connectivity Services

The evolution of the BDC is bi-directional and uses entities for direct connectivity with LOB applications / databases.

REST

This was one of the coolest features added to SharePoint due to the addition of WCF.  SharePoint content can be quickly accessed via simple HTTP and it will return XML or JSON.  This could prove very interesting.

Office 2010 real-time collaboration

Office 2010 fully supports real-time collaboration with robust features to sync and protect data while allowing users to work together on documents at the same time.

SharePoint Workspace

Gone is Groove, and here comes SharePoint Workspace.  You export whole sites and all their content onto your desktop, see changes, sync versions, etc.

Visio Services

Bring your Visio diagrams to the web and treat the elements as assets in code allowing you attach business logic to these diagrams to visualize LOB data in diagrams in real-time.

Access Services

Create entire applications in access and "convert" them to SharePoint web applications with simple synchronization.

RIP Shared Service Provider

Now we have Service Applications that are independent and available to any web applications and even to other farms!

Visual Studio 2010 and SharePoint Support

New project types and deployment options are going to make this a lot easier for developers.

SharePoint Designer 2010 and much improved workflow

SPD 2010 was overhauled.  Amongst other things is the ability to build reusable workflows, export them into Visual Studio, and package them as WSPs for deployment.

Windows 7 and Vista Development Supported

Now you can develop on workstation-grade operating systems.

FAST Search Integration

FAST is now fully embedded into SharePoint as an optional upgrade.  And it is AWESOME!

 

I will try to explore and blog about each of these in detail as I test, play, and learn from the beta releases of SharePoint 2010 in the coming months! 

It was a great conference and I am truly excited about what is to come!

-Ryan

SPC 2009 Day Three

Highlights from the day

Steve Walker and Joe Indelicato (of Chevron, Joe formerly of the Houston Texans) put on a good presentation about using BI in both cases to improve the business. At the Texans, Joe pioneered using Microsoft technologies to data mine and exploit weakness in other teams. Joe discovered statistical trends in which plays were most likely to be called, and tendencies of players that had the lowest aptitude test scores in Combine (run plays with motion straight at them – they’re more likely to get confused and falter). At Chevron, they are using BI and geospatial dashboards to surface information about the performance of wells and actions that need to be taken on them.

Kraft detailed their migration of 270+ consumer-facing web sites to SharePoint. The case study available on Microsoft.com was detailed – a $2.2M cost savings by moving the sites to SharePoint, while providing a flexible architecture to support unique branding and creative control of each product’s web page. The combined sites have 100M page views per month, with several billion and 100M dollar brands to support, and 98,000 employees as well as external ad agencies who want control. The migration plan demanded that creative efforts were separated from data processing. An architecture leveraging XML, XSL, CSS, Web Parts, and a clever automated packaging and promotion scheme fit the bill. Rollback capability was provided by checking current pages into a document library before promoting new pages. Case study: Available at microsoft.com

Two folks from Microsoft detailed their migration of an internal application for “After the fact Purchase Order” (ATFPO) approval from MOSS 2007 to SharePoint 2010. Many of the items they had to roll by hand to create a security trimmed view of ATFPO’s for users in 2007 were now available off the shelf in 2010 using BCS. They were able to remove many of the “moving parts” from their solution, shrinking development time from 480 to 80 hours, and lines of code from 2763 to 446! As we saw clients leveraging SharePoint 2007 to speed up development cycles for LOB applications over traditional ASP.NET, I believe we’ll see the trend increase exponentially with SharePoint 2010.

Jones Lang Lasalle has bet on SharePoint in a big way, using the platform to support their rapidly-growing company. Leveraging MOSS 2007, they were able to capture web leads for the first time (0 – 5000 in the first year), increase the usage of their research downloads four times, and invert their development/maintenance resource allocation from 30%/70% to 70%/30% respectively. Their array of hundreds of sites and several different languages to support (as well as metric/English measurement and other localization considerations) made MOSS the obvious choice. They are currently looking at upgrading to SharePoint 2010, and as one of the larger SharePoint 2007 installations, they provided some interesting data on their pre-upgrade check. Almost all of their current features migrated with little to no intervention, which bodes well for companies considering the move to 2010. Case study: Available at microsoft.com

Day Two of the SharePoint Conference 2009 (SPC)

There were more in-depth info on SharePoint features and client stories, as well as analyst views on Day 2. Booz Allen Hamilton had a great story about their intranet’s social networking features, and how they drove adoption in a conservative environment where such ideas might normally be resisted. BAH used FAST Search, SharePoint, and some home grown solutions to provide a portal where people could post their availability for projects and managers in need of resources could find out about them, their reporting structure, and skills. They showed off a neat org chart tool that allowed you to dynamically browse groups and reporting relationships. Most of their organization was from tagging, and they let people show a little character in the portal in interests (like gardening, reading, golf, etc). They believe that this helps add a more rounded, human side to the profiles, and also helps suggest groups to form within the organization.

Bamboo Solutions showcased the new project management features in 2010 and in their product Project Management Central, with the help of Dax Sy and Julie Auletta. The combined feature set coupled with SharePoint 2010’s extensibility begs the question – is there anything that full-blown MS Project Server can provide that this solution does not? Portfolio management at the top, tasks, dependencies, updating percent complete on tasks, integration with desktop MS Project, creating dashboards, and alert emails you can format for milestones. I’m going to investigate this more, as many of our clients are interested in solutions like this and have shied away from full-blown MS Project Server thus far.

The session with Forrester on custom development in SharePoint was interesting. Their basic thesis – decide how much you want to get involved in SharePoint and go in with your eyes open. Do you consider SharePoint an application? An app plus “it runs our intranet”? Or do you consider SharePoint an enterprise application and integration platform? If you want to get into advanced projects, realize they are advanced and require a full-strength commitment of resources for development, testing, QA, deployment, and maintenance as any other enterprise application would. Many cases where people were unhappy with SharePoint seemed to stem from starting out with treating it as an application, then wanting to use it for more advanced projects while still wanting to treat it as “just an application” and not a development platform.

Other important ideas:

SharePoint is being extended in 2010 to allow you to leave current systems in place and have a “single source of truth” (SSOT) that you can surface through the portal, with optional read/write capability. This is a small refinement to the existing BDC but an important idea in that you can leave the data where it lives (PeopleSoft, SAP, SQL Server, etc) and not have to replicate it to SharePoint to expose it. This allows you to make SharePoint the “one stop shopping” portal for information in the company without a lot of expensive integration.

SSOT is expanded further with the REST-ful implementation of items like charts in SharePoint 2010. Common use case: There is a chart showing sales for the past four quarters, and a projection of the next two quarters. This chart lives in Excel, gets emailed around the company, and is copied into dashboards, PowerPoint, etc. What happens when the data in the Excel spreadsheet is updated and the chart changes? There is no way to know how many other places the chart has been copied, so stale data is inevitable. In 2010, you can move the data online and publish the chart in SharePoint to a known URL, and link the other items to this URL. Any changes will be picked up by the downstream consumers when the chart changes. The usual alerts and notifications can also be enabled to know when the chart changes.

Speed and Usability – don’t forget about them! In the session with Electronic Arts, they talked about the importance of responsive systems that share information efficiently. They advocated using Firebug and ySlow on your web apps to help figure out where performance can be improved. Their SharePoint implementation removed much of the default JS/CSS in pages in favor of a lightweight style definition (just 32 lines of CSS and 12 images to create a “skin”). They also cited Jakob Nielson’s “F-Theory”, that people scan and read things in a pattern similar to the capital letter F. The implication for SharePoint page layout is to create your web parts and then try a two or three column layout approach putting the most important items in the top left, top right, and middle left.

MS SharePoint Conference Day One

Syrinx is here in force at the Microsoft SharePoint Conference 2009 in Las Vegas, NV. The Mandalay Bay is packed with over 6,000 people attending the conference from all over the world. The morning was spent in a keynote with Steve Ballmer and a demo of the new SharePoint 2010 capabilities. Highlights for those that cannot be here:

  • SharePoint 2010 Beta release scheduled for next month (November 2009)
  • Final release sometime in H1 2010
  • Windows 7 and Vista will be supported for developer platforms, and there is a developer dashboard built in that helps with profiling code. Downside: New developer tools are designed to work with 2010 only, not MOSS 2007.
  • SharePoint Server is 64 bit only
  • Better cloud support, allow uploading code and customizing SharePoint Online, and to mix and match cloud and “on premises” installs
  • Many more SKU’s in this release, four quadrants of products based on Intranet/Internet and cloud/on premises
  • Great demo’s of Access Services, Visio Services, SharePoint Workspaces (the new ‘Groove” for working disconnected), FAST Search, BCS (the new BDC – now with read/write capabilities and auto-generated CRUD operations for back-end LOB systems), PowerPivot (super Excel – handle 100M rows in one spreadsheet QUICKLY), co-editing of documents by more than one user at a time, “Insights’ the new PerformancePoint
  • Scalability – 1M+ items in a list/folder, 10M+ in a document library, 100’s of millions across a farm.
  • Better ability to create taxonomy or informal tagging to build a “folksonomy”
  • PowerShell admin ability with 500+ commandlets shipped at release
  • “Visual Upgrade” to run your 2007 to 2010 migration and allow users to cut over on a page by page basis as they are ready (Unanswered question – does this just apply to look and feel/chrome or does this affect web parts, etc? What don’t you see if you do not turn on the 2010 version?)
  • Streaming video is supported – make your own “ShareTube” and control bandwidth, allow lookahead, etc.
  • Better deployment capabilities, including the ability to build a solution in SharePoint Designer and have it move to different lists/libraries, or to upsize it to be worked on in Visual Studio.

Some General SharePoint product differentiators and customer feedback were mentioned

  • Customers are responding very well to a platform that allows them to solve so many needs – there really is not a competing product that does everything SharePoint does or gives you the value it does
  • SharePoint is cost effective by saving money three ways – less for licensing than trying to assemble several other competing products to do the same things, less to implement as it gives you so much out of the box, less to maintain and support as you have one platform to cover the many needs and one admin/developer skill set
  • Favorite first projects: Intranets, Dashboards, Project Management portals, IT Service portals, moving paper-based LOB systems online, Content Management
  • Microsoft is betting on the platform in a big way. Customers are as well. Great sessions from clients Tyson Foods and Global Crossing on their early SharePoint 2010 experiences. The Office integration done by Tyson to solve real LOB issues was exceptionally impressive.
How about some (almost) free Business Intelligence?

I spent a lot of time at the Microsoft office last week in Waltham, including the Quarterly Partner Briefing on Tuesday 3/24. One of the sessions I attended on BI put on by Bob Lincavicks and Tara Seppa clarified some recent announcements about PerformancePoint being rolled into SharePoint. When I first heard about this in January I did not understand it, but after last Tuesday the roadmap and economics are much more clear.

Summary: If you have Microsoft Office SharePoint Server, MOSS Standard Cal, MOSS Enterprise Cal, and Software Assurance, you are now entitled to get PerformancePoint Server at no additional charge starting yesterday 4/1/2009. No, this is not an April Fools! You download some new bits and can install and use them. PerformancePoint is Microsoft's full-blown BI platform that sits on top of SQL Server (SSIS/SSRS) and allows you to do all the reporting, dashboarding, scorecards, drill downs, etc until your heart's content. Learn more about PerformancePoint here: http://www.microsoft.com/bi/products/performancepoint-server.aspx
and about the licensing announcement here: http://www.microsoft.com/bi/products/announcement.aspx

Most companies we have run into are either already in the situation stated above, or in one of the two following "YOU ALMOST HAVE IT!" states:

1. Have MOSS ECALs as part of a package they purchased, and have considered implementing MOSS (may be running WSS at the moment, or not)

2. Have MOSS server with standard CALs

If you are in either situation, consider stepping up to Microsoft Office SharePoint Server (MOSS) with Standard & Enterprise CALs w/Software Assurance. Chances are your step-up costs won’t be that big, and will pale in comparison to PerformancePoint's old $25K/server & $195/Cal price tags. You'll get the Enterprise capabilities of MOSS (Excel Services, Forms Services, BDC, etc) which are worth it in and of themselves, and then be free-rolling on the PerformancePoint. In 2009, who doesn't want to use a tool like PerformancePoint to get a better handle on the strategic and operational aspects of their business to spot trends, make better and more timely decisions, and target cost cutting? Getting this capability as part of the package can help loosen up budgeting that might not otherwise apply.

Fine print: PerformancePoint will release one more Service Pack as a standalone product this summer, and then if you INSISTED on running it standalone forever, mainstream support would end in 2013, and extended support would end in 2018. See details here: http://support.microsoft.com/lifecycle/?p1=12922 Microsoft will be rolling the Monitoring and Analytics pieces of PerformancePoint directly into SharePoint in the Wave 14 (next year this time) timeframe. When they do that they will drop the Planning module from PerformancePoint. There are three capabilities currently in PerformancePoint (Monitoring, Analytics, and Planning). If you're not using Planning now (everyone in the above scenarios) you're not going to miss it and don't need to worry about it.

Windows IT Pro Article on Workflow Released

I wanted to let everyone know I completed an article on using SharePoint workflow with the emphasis on what you can do out of the box with MOSS entitled:

SharePoint Workflows

Transform business processes without writing code. 

It has been published in Windows IT Pro magazine.  Here is a link to the article:

http://windowsitpro.com/article/articleid/101350/sharepoint-workflows.html

It is also in the April print edition as well.

-Ryan

Presentation on Enterprise Search at Microsoft

I recently presented a case study at Microsoft on 3/26 about work we have done at Gilbane Building Company on custom search components within their enterprise.  I had some requests for the presentation and I wanted to provide a link to the powerpoint.  Thanks again to Microsoft for hosting the event, and Jon Rider from Gilbane.  Here is the link to the presentation.

-Ryan

Making Business Data Actionable with Dashboards

Business intelligence is a rapidly growing sector of IT development and expenditure budgets. Products include financial modeling, data analysis, data mining, reporting and charting tools. The large vendors, Oracle, IBM and Microsoft, all have products in this space and continue to develop new ones and refine the existing ones. These tools generate huge amounts of additional data and charts about the business data. This, in turn, creates a new problem:  how do you make all this data readily consumable and, more importantly, actionable? How do you summarize the data? The answer is a BI dashboard.

Read the full article

Customized Content Rating for SharePoint

I wanted to share with you a recent client undertaking involving adding "star rating" and comments to SharePoint content.  As usual, clients prefer not to build everything from scratch, so I looked what was available via 3rd party options and found 2 potentially viable solutions:

SharePoint Document Rating System  from codeplex:  http://www.codeplex.com/spdocrating and a licensed offering from KwizCom:  http://www.kwizcom.com/

At the time, the codeplex solution seemed a little more difficult to deal with, requiring content types and multiple columns in a list to function.  These column also appeared to be based on non-standard formats, and it was not straightforward to use the columns as managed properties to create more fine-tuned search options.

Since the KwizCom solution was simply a custom field type installed into SharePoint based on a common decimal base type, it seemed much easier to implement.  The downside was that it was some custom code, not open source, and it was entirely obfuscated so when I needed to make some adjustments based on my requirements, I was really stuck with what they gave me.  Here's what I did in case someone is thinking about doing this:

I added their custom field to my SharePoint environment and created a site column from it called Ratings.  Below is a screen shot of what this looks like in a list/library

ratings1 ratings2

The above shows what the column looks like and what it shows you when you hover over the item.  When you click on the item you get a pop up where you can rate and read comments similar to this:

ratings3

ratings4

Ok, so the easy part is done:  Install the product and add it to a list, and fill out some data.  They give you that for free :)  Now I had to come up with my own solution for the next 2 problems.  First, I needed to include the ratings for documents in search results.  It turns out to be pretty easy, but there were a couple wrinkles.

1.  I had to copy some images over from the KwizCom installation location to where the layout images live in the 12 hive here:  C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\12\TEMPLATE\IMAGES

2.  Then I had to modify the Search Results page (Search Core Results) to include my column in the XML, and then add a series of XSL "when" to display the star rating image AND the link to the comments as this was a requirement.

<xsl:when test="contentrating='1'"> - <img align="top" style="cursor:pointer;" onclick="window.ratingelement=this.parentNode;commonShowModalDialog('/_layouts/RatingRedirect.aspx?ItemURL={url}&amp;SiteName={sitename}&amp;a=1' ,'dialogHeight:450px;dialogWidth:350px;scroll:no;toolbar:no;status:no;resizable:no;', null, this.parentNode);" src="_layouts/KWizCom_RatingSolution/Images/1.0.gif"/></xsl:when>

The savvy of you may look at this XSL and wonder what "RatingRedirect.aspx" is.  Well, this is something I had to come up with because the KwizCom code is locked down.  Essentially I had to write a gateway page that took the querystring data available in the search results page and send it to a location that had the ability to look up the proper data required by the KwizCom page to load rating details.  The aspx page code I wrote looks like this:

public partial class RatingRedirect : System.Web.UI.Page
   
{
       
protected void Page_Load(object sender, EventArgs e)
       
{
           
ProcessRedirect();
       
}

       
private void ProcessRedirect()
       
{
           
string itemURL = Request.QueryString["ItemURL"];
           
string siteUrl = Request.QueryString["SiteName"];
           
string destination = Request.QueryString["a"];

           
using (SPSite mySite = new SPSite(siteUrl))
           
{
               
using (SPWeb myWeb = mySite.OpenWeb())
               
{
                   
SPListItem item = myWeb.GetListItem(itemURL);
                   
if (item != null)
                   
{
                       
if (destination == "1")
                       
{
                           
Response.Redirect(item.Web.Url + "/_layouts/KWizCom_RatingSolution/RatingPopup.aspx?itemId=" + item.ID + "&listId={" + item.ParentList.ID + "}");
                       
}
                       
else if (destination == "2")
                       
{
                           
Response.Redirect(item.Web.Url + "/_layouts/KWizCom_RatingSolution/CommentsPopup.aspx?itemId=" + item.ID + "&listId={" + item.ParentList.ID + "}");

                       
}
                   
}
                   
else
                   
{
                       
Response.Write("<br>   Sorry, this item cannot be rated.");
                   
}
               
}
           
}

       
}
   
}

The basics here are that I need to some ListItem data that is completely unavailable at the search results page.

Also consider that only list items can contain ratings.  Much of the unratable content can be exluded from search results using contentclass exclusions in your search scopes, but the one that tripped me up was a standard site aspx page.  If the page did not live in a library but was returned in search results, it would display with zero ratings.  When a user clicked on the details they would receive an error because this was an unratable item.  You see my rudimentary error handling section in the code above to at least inform people about the status.

We also added a higher level check in the XSL to only return rating data from content sources that actually had the rating installed.  Other SharePoint web applications or site collections within the SSP that does not contain rating data needs to be excluded.

These changes allowed my search results to show the ratings details AND allowed users to view the comments AND add their own comments right from the search results page.  The only hiccup is that until another crawl is run, the changes won't be shown in the search results because that data is pulled from the index and not in real time.  A small price to pay.

ratings5

Finally, I had to deploy this.  Essentially the client wanted to add this to any document libraries that already existed in their site collection.  It seems every client requires me to write a tool that iterates over a site collection and checks for something in each web/list.  It's either inheritance, permissions, features, etc. that need to be set for every list if some condition is met.  So I had some code I could re-use.  I won't paste the whole thing here, but it was pretty simple:

I iterated over every site and did the following:  checked for each list to see if it inherited from base templates of document library or link lists.  If so, I iterated over the fields to see if the Rating field was present.  If not, I would add the field to the list, then add it to the default view of the list. 

Then you have to "tickle" the list, and un-tickle it.  This one was critical.  Due to the nature in which this data is stored, there is an inherent bug with the KwizCom solution.  Their design created a hidden list per web that holds the rating data.  This list is not created until a least one rating is made in the web.  This code must not run with elevated permissions because users without proper permissions to create the list will receive an error.  It's odd that they missed this because their solution only requires read access in order to rate items, so they must have written elevated permission code elsewhere in their solution.

At any rate, the tickle adds a rating to the first item in the list, updates the item, then removes the rating.  This ensures the container list exists moving forward.

All in all it did not take too long to implement and the 3rd party price was pretty inexpensive.

I hope this helps,

-Ryan Thomas

Deleting Deeply Entrenched Site Columns - Another Reason for Governance

I was recently called back to a previous client to help with a list of issues and tasks they had accumulated, and I was surprised to find one very difficult one:

The client complained about seeing multiple duplicate columns available for views and filtering in one of their large document libraries.  I knew they used InfoPath, so I had assumed that they had run into the problem I blogged about here:  Automatic Creation of InfoPath forms - not as easy as I thought regarding InfoPath re-creating duplicate site columns when in certain cases of re-publishing forms.

This client had not done anything like this with InfoPath, instead they had created approval workflows (out of the box) at the web/site level and applied them Content Types, so far so good.  Each of the multiple Content Type had their own approval workflows, and the columns appearing multiple times all happened to be the name of the column created as the WorkflowStatus type used by SharePoint to maintain the state/status of the workflow.  I'm not exactly sure what happened,  but I'm assuming they created, deleted, re-created, etc. these workflows using the same name a bunch of times, possibly at different levels within the sites, since some of the Content Types lived at the Site Collection level.  This caused this column to keep showing up (same Display Name, unique Internal Name) multiple times.

Although normally not a big deal, this was a real bugger to get rid of.  The UI won't let you drop the field because it is read only on the list, and it's also attached to the Content Type.

Untitled picture4

Here is how I solved it:

1.  Gather up all the data to make sure you know which field is current and legitimate by looking at the data contained within it.  Keep at note of the internal name by sorting on it in a list view and looking for the SortField querystring parameter.

2.  Delete it from the Content Type first by going to list settings and clicking on a your Content Type link.  Then click on any of the columns in this list to get to the "Change List Content Type Column" screen.  We need to replace some variables in the querystring to locate our hidden field/column.

First, replace the Field parameter with the *Internal Name* of your field.  You have that from #1 above.

Second, you need to replace the Fid (FieldID) parameter with the correct GUID of the field you want to delete from the Content Type.  The easiest way for me to do this is to use SharePoint Manager 2007, an invaluable tool that is free from CodePlex.  Here is a screenshot where I can see and verify the Internal Name and ID.  You can see the duplicate field names under the "Customer Specification" Content Type in the left tree view.

Untitled picture5

Once you have replaced both of these values MAKE SURE YOU FORCE A BROWSER RELOAD.  The best way to do this is copy the new url and load it in a new browser window.  You should see your column details in the page.  If you just swap variables and hit "Delete" the data in the page may still be pointing at the legitimate column you clicked on to get here.

3.  Delete the Field from the actual list.

I was not able to find a way to delete the field from the list through the UI no matter how much trickery or querystring replacement I tried.  Fields need to have their Hidden and ReadOnlyField status set false before they can be deleted, and SharePoint Manager 2007 wouldn't let me do this for some reason.  I had to resort to a console application.  Quick and dirty code pasted below.

                SPList isoDocs = web.Lists["Documents"];
               
SPField field = isoDocs.Fields[new Guid("3e68ae11-e4a7-4bfe-aca9-d1cac96c14d1")];
               
Console.WriteLine(field.InternalName);
               
LogMessageToFile(field.InternalName);
               
field.Hidden = false;
               
field.ReadOnlyField = false;
               
field.Update();
               
isoDocs.Fields.Delete(field.InternalName); 
 
After tediously looking at each column to figure out what was the correct one and determine which ones to delete through the above process, I was able to clean up the environment. 
 
This brings up an important issue I try to stress with all clients:  Governance.  In most modern organizations there is enough spare hardware to set up a development/test environment for SharePoint and to restore a copy of your production content DB to test changes against a safe, but duplicate environment.  Having these options in place will definitely save you time and money over the long run.  I almost never make changes to a production environment, even simple ones, without first testing it against a copy of that environment and evaluating the effects.  Some planning up front about having the infrastructure in place and a set of change rules to follow could avert disasters.
 
****UPDATE****
I wanted to let everyone know that the column duplication and inability to delete them issue was easy to reproduce, and in my opinion should be a bug in SharePoint.  If you create an approval workflow and attach it to a content type, it creates a field in the content type and a field and column in the list where the content type resides.  If you delete the workflow the field and column remains, unable to be deleted because of the read-only status.  Be careful of this in the future.
 
I hope this helps,
-Ryan Thomas
Automatic Creation of InfoPath forms - not as easy as I thought

I recently completed what I estimated to be a small project of taking an existing set of InfoPath forms that represented Content Types and Site Columns for a client's yearly employee review process.  Last year they had to manually create a number of forms for each employee to be filled out and eventually sent to Human Resources.  If each employee has an average of 6 forms (they do peer reviews) and a manager is required to pre-fill each form and manage the permissions of said form for each employee, a significant amount of time is wasted. 

I estimated that in about a week or two we could write a web part to collect all the data, load up and pre-fill each form's XML, add it to the doc library, and set the permissions for the forms throughout their lifecycle based on the current status of the review process.  It will take too long to go over the whole project/code-base, so I'll highlight the important areas.

1.   Web Part to collect employee, supervisor, reviewer users and some dates, etc.

 Untitled picture

2.  Event Handler on the form library to look at the status as updated by the form upon submit.

Problem 1:

I thought I could be clever.  Knowing the XSN generated from InfoPath contained the underlying XML file I would need to populate and save in SharePoint, I thought I could use the foundation from this blog post to get to that file:  http://www.kindohm.com/archive/2008/01/10/programmatically-create-an-infopath-form-instance-from-xsn-template.aspx

It is a great concept, albeit a little hokey.  The basic concept is to use the XMLFormView control to load an instance of an XSN, then extract the XML from it and use it.  The problem is that you can't get the control to initialize unless it is actually run in a page.  So, the poster put the form in another aspx page and calls it via his code (in my case the web part) through the WebClient or HTTPWebRequest and return it as a Response Type of XML.  This solution works great in Windows Server 2003, but Windows Server 2008 it only throws 401 Unauthorized errors.  It tried everything, every different type of credential I could.  The only time it worked in Server 2008 is when I used the default app pool in IIS, and it has some different settings (Network service account, etc) that I wouldn't want to use for MOSS.  At any rate I could not get around this problem even after hitting up some MOSS MVPs that I have tremendous respect for.

Problem 2:

I worked around Problem 1 (hopefully temporarily) by saving my InfoPath forms as source files and manually dropping a copy of the XML container in the form library where the XSN lives.  This created Problem 2.

If you create your InfoPath form on your local machine, the resulting XML does not share the same XML processing instructions as those that are created when publishing to a SharePoint library.  So, I had to manually replace the instructions in each XML file as it was created.  I had to use scientific method to find out which instructions were causing the form to load improperly, but it came down to these two items:  href and solutionversion.  Href is obvious, the xml needs to point to the library that is hosting it so Forms Server knows where to process the form.  Until it is published to the library this value is not set, so I had to set it by hand.  Code snippet below:

XmlNode oldPiNode = xmlForm.SelectSingleNode("/processing-instruction(\"mso-infoPathSolution\")");

           
// delete a processing instruction
            XmlNode ndDel = xmlForm.SelectSingleNode("/processing-instruction(\"mso-infoPathSolution\")");
           
xmlForm.RemoveChild(ndDel);

           
// create a new processing instruction
            Match mHref = Regex.Match(oldPiNode.Value, @"href=\""(.*?)\""");
           
if (mHref.Success)
           
{
               
oldPiNode.Value = oldPiNode.Value.Replace(mHref.Groups[1].Value, "http://xxxx.xxxx.com/review/Review/Forms/" + infoPathTemplateName);
           
}

Solutionversion turned out to be completely obnoxious.  By default, the solution version in the "save as source" XML is exactly 3 revisions ahead of the one published to SharePoint.  So I needed to manually decrement my XML file so Forms Server could properly load it: 

Match mSolVer = Regex.Match(oldPiNode.Value, @"solutionVersion=\""(.*?)\""");
           
if (mSolVer.Success)
           
{
               
string solVer = mSolVer.Groups[1].Value;
               
int smallver = Convert.ToInt32(solVer.Substring(6));
               
int smallverDecremented = smallver - 3;
               
oldPiNode.Value = oldPiNode.Value.Replace(smallver.ToString(), smallverDecremented.ToString());
           
}

Since processing instructions are just whole single nodes, I couldn't easily just replace individual attributes.  Instead I had to grab the existing entire node and replace those elements I needed to update via string manipulation, delete and re-add my new processing node back into the XML.  This all seemed to work, and can be completely removed if I can get the security issue in Problem 1 fixed at a later time.

Problem 3:

This problem isn't specific to InfoPath or this solution, but has come up enough that some people new to this game should be aware of.  If you want to give a set of users rights to add items to a document library, but then only see and manage their own items, you can't do it.  It works fine with standard lists (an advanced setting on Lists) but this was left out for Document Library and child lists.  Why?  I'm not sure. 

It certainly makes it difficult on projects such as these where you need to assign users certain items, and list item permission by hand can be tedious and error-prone. 

My common solution to this problem (when I don't have workflow as my manager of the data) is to use an event handler on the list to look at the appropriate metadata and content type and determine what needs to happen.  It is sort of a mini rules engine for permissions processing and it looks like this:

First, override your events (ItemAdded and ItemUpdated for example) and check the Content Type: (feel free to use more descriptive terms, the names have been changed in my code to protect the innocent)

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

            switch (properties.ListItem.ContentType.Name)
           
{
               
case "Part1":
                   
UpdateFormOne(properties);
                   
break;
               
case "Part 2":
                   
UpdateFormTwo(properties);
                   
break;
               
case "Part 3":
                   
UpdateFormThree(properties);
                   
break;
               
case "Part 4":
                   
UpdateFormFour(properties);
                   
break;
               
case "Part 5":
                   
UpdateFormFive(properties);
                   
break;
               
default:
                   
break;
           
}
       
}
 
What does the Update code look like:
 
private void UpdateFormFive(SPItemEventProperties properties)
       
{

           
string formStatus = properties.ListItem["Form Status"].ToString();

           
XmlDocument xmlForm = new XmlDocument();
           
Byte[] fileBytes = properties.ListItem.File.OpenBinary();
           
MemoryStream stream = new MemoryStream(fileBytes);
           
xmlForm.Load(stream);

           
XmlElement root = xmlForm.DocumentElement;

           
string evaluatorUserKey = root["my:employeeUserKey"].InnerText;
           
string supervisorUserKey = root["my:supervisorUserKey"].InnerText;

           
SPUser evaluatorUser = properties.ListItem.Web.SiteUsers[evaluatorUserKey];
           
SPUser supervisorUser = properties.ListItem.Web.SiteUsers[supervisorUserKey];

           
List<SPUser> userList = new List<SPUser>();

           
switch (formStatus)
           
{
               
case "Not Started":
                   
userList = new List<SPUser>();
                   
userList.Add(evaluatorUser);
                   
userList.Add(supervisorUser);
                   
Utilities.RemoveContributePermissions(properties.SiteId, properties.ListItem.Web.ID, properties.ListId, properties.ListItem.ID, userList);
                   
Utilities.BreakandSetContributePermissions(properties.SiteId, properties.ListItem.Web.ID, properties.ListId, properties.ListItem.ID, userList);
                   
break;
               
case "Started":
                   
break;
               
case "Complete":
                   
break;
               
case "Submitted to HR":
                   
userList = new List<SPUser>();
                   
userList.Add(evaluatorUser);
                   
userList.Add(supervisorUser);
                   
Utilities.RemoveContributePermissions(properties.SiteId, properties.ListItem.Web.ID, properties.ListId, properties.ListItem.ID, userList);
                   
Utilities.BreakandSetReadPermissions(properties.SiteId, properties.ListItem.Web.ID, properties.ListId, properties.ListItem.ID, userList);
                   
break;
               
default:
                   
break;
           
}
           
stream.Close();
       
}
 
Some explanation needs to be provided here:
 
I load up the actual form because I stored some data in there.  Without workflow, I needed a location to manage the users that will need access at various points, and the form itself proved to be a nice container.  evaluatorUserKey and supervisorUserKey are used to create SPUser objects to pass to the permissions methods.  I then look for the current status to determine what permissions to set.

Here is what the permissions setting code looks like:

internal static void BreakandSetContributePermissions(Guid siteID, Guid webID, Guid listID, int listItemID, List<SPUser> userList)
       
{
           
SPSecurity.RunWithElevatedPrivileges(delegate()
           
{
               
using (SPSite site = new SPSite(siteID))
               
{
                   
site.AllowUnsafeUpdates = true;
                   
using (SPWeb web = site.OpenWeb(webID))
                   
{
                       
web.AllowUnsafeUpdates = true;
                       
SPList list = web.Lists[listID];
                       
SPListItem item = list.GetItemById(listItemID);

                       
try
                       
{
                           
if (!item.HasUniqueRoleAssignments)
                           
{
                               
item.BreakRoleInheritance(false);
                           
}

                           
foreach (SPUser user in userList)
                           
{
                               
HandleEventFiring eventFiring = new HandleEventFiring();
                               
eventFiring.CustomDisableEventFiring();
                               
item = SetItemLevelPermissions(item.Web, item, SPRoleType.Contributor, user.ID);
                               
item.SystemUpdate();
                               
eventFiring.CustomEnableEventFiring();

                           
}
                       
}
                       
catch (Exception ex)
                       
{
                           
//Add error handling code here
                        }
                   
}
               
}

           
});
       
}

This code is pretty straightforward except for HandleEventFiring which is something none of you have seen before,  This is a custom class I created to handle versioning issues on list items, etc.  My full blog post about how and why I use it is here:  http://blogs.syrinx.com/blogs/sharepoint/archive/2008/11/10/disabling-event-firing-on-splistitem-update-differently.aspx

And finally, the code to set the actual permissions:

        private static SPListItem SetItemLevelPermissions(SPWeb setSPWeb, SPListItem setListItem, SPRoleType setRoleType, int userID)
       
{

           
SPUser user = setSPWeb.SiteUsers.GetByID(userID);
           
SPRoleDefinition roleDefinition = setSPWeb.RoleDefinitions.GetByType(setRoleType);
           
SPRoleAssignment roleAssignment = new SPRoleAssignment(user.LoginName, string.Empty, string.Empty, string.Empty);
           
roleAssignment.RoleDefinitionBindings.Add(roleDefinition);
           
setListItem.RoleAssignments.Add(roleAssignment);
           
return setListItem;
       
}

That's my solution for one way (without custom workflow) to manage document permissions to allow everyone to contribute, but then lock down the documents upon creation and updating.

Problem 4:

Another concern with InfoPath I ran into was publishing updated forms to SharePoint and mapping fields to site columns.  InfoPath supports creating site columns locally and mapping them to it's local XML data fields to be updated automatically upon submission. 

Upon publishing changes to a test environment I didn't realize that it is possible for these fields to get out of sync.  InfoPath protects itself by creating brand new site columns with the same name.  From the SharePoint UI and InfoPath perspective everything looks great until you see your column names showing up twice in list management and view creation screens.  Your code also starts breaking as it's looking for a certain internal name that is no longer being populated.

Basically SharePoint just creates a new site column with the same display name, but creates an internal name like columnname1 or columnname12.  The fix for this is DON'T DO IT IN THE FIRST PLACE.  It is a pain to hunt down the correct columns and delete them (after deleting your content type form because of the "in use" issue) 

Instead, at this screen:

Untitled picture2

Click "Modify" and make sure the local field is mapped to your correct site column.  If you see (none:  create new site column) you need to change it unless this is a brand new field.

The screen below shows how to "re-map" to an existing site column created by InfoPath:

Untitled picture3

Well, I know this post was long, and it didn't cover everything I did, but I tried to cover the parts that caused me some hang-ups.  Despite losing 2.5 days alone to the security problem I still was able to deliver the mini-project on time.  There were some things I would have much rather done differently, but due to the issues and time constraints I had to get something out there and working.

I hope this helps,

-Ryan Thomas

Grouped SPGridview Exceptions

Yesterday I spent many hours trying to solve what should have been a simple issue - grouped views in a SPGridview.

 I was building a web part that used an embedded SPGridview - this was part of a template I created used by a TemplateBasedControl which was the created by the Web Part. All was working fine until I decided to add grouping. I set the GroupField, AllowGrouping, and AllowGroupCollapse properties:

<SharePoint:SPGridView AutoGenerateColumns="false" runat="server" ShowHeader="true" ShowFooter="true"
            GroupField="GroupField" AllowGroupCollapse="false"
            AllowGrouping="true"
 DisplayGroupFieldName="false"
            ID="inventoryGrid" AutoGenerateDeleteButton="false" AutoGenerateEditButton="false"
            AutoGenerateSelectButton="false">

The control rendered fine until a postback happened - then I started getting exceptions, relating to SPMenuField. Since I was not creating a SPMenuField I was confused. After much digging I came across some helpful hints - pointing to postback issues with SPGridview.

Of particular help was http://www.thesug.org/blogs/patrickr/Lists/Posts/Post.aspx?ID=2 . However I simplified my code down and it seemed to work for me. My solution involved creating my own Class derived from SPGridview and then overriding the LoadControlState method as shown in the above post but since my control was being used in a webpart and I cannot modify the page - I just called DataBind directly:

So my class code looks like:

 public class LTCSPGridView : SPGridView
 {
     protected override void LoadControlState(object savedState)
        {
            base.LoadControlState(savedState);
            if (this.DataSource == null)
            {
                this.DataBind();
                this.InvokeRequiresDataSource();
            }
        }

        public event EventHandler RequiresDataSource;

        protected void InvokeRequiresDataSource()
        {
            EventHandler handler = this.RequiresDataSource;
            if (handler != null)
            {
                handler(this, new EventArgs());
            }
        }
    }

My modified Template definition then looks like:

<ltc:LTCSPGridView AutoGenerateColumns="false" runat="server" ShowHeader="true" ShowFooter="true"
            GroupField="GroupField" AllowGroupCollapse="false" AllowGrouping="true" DisplayGroupFieldName="false"
            ID="inventoryGrid" AutoGenerateDeleteButton="false" AutoGenerateEditButton="false"
            AutoGenerateSelectButton="false">

 

This fixed my problems - I hope it helps someone else.

Ian.

More Posts Next page »