Thursday, July 09, 2009
e-office summer school
Monday, May 18, 2009
Content types are not document templates!
Microsoft introduced content types in MOSS 2007. Content types are defined by Microsoft as follows: “A content type is a reusable collection of settings you want to apply to a certain category of content”. In practice, they consist of a collection of site columns and some other settings (like workflow).
For content types deriving from document parent types, a document template file can be attached (for example a Word document template).
This becomes visible to end users when a content type is used in a document library: under the New button, the content type appears and when clicking it, the appropriate application will open based on the defined template.
User perception
This is how most people associate the content type: something related to the application (Word, Excel etc). Seems logical because an application opens when they create a new item based on that content type. Example: we have a document content type “Project Initiation Document” that we use in a document library. A blank Word document is set as the associated template file so when a user clicks “New, Project Initiation Document”, Word opens.
In the field, I’ve noticed content types like “Word document”,
“Excel document” etc. being used solely to open the appropriate application, without any specific site column for meta information. This strengthens the user perception of “content type = template”.
Here’s the catch
Content types are great, but what if I have one called “Calculations” and sometimes use Word and sometimes Excel for its contents? The content type only allows me to associate one template file. If I have set it to use Word, I always get Word when clicking the content type from the New button. Reality is that people often use various document types to achieve similar objectives; I even made my CV in PowerPoint once.
A workaround would be to create the Excel document locally, upload it to the library and then choose the content type. However, how do you explain your average user to create some documents via the New button and some documents locally? Also, how do you make sure the locally created document is based on a template you control centrally?
This is where I think Microsoft took a wrong shortcut, connecting the content type and the document template so intimately.
How it should work
Here’s how I think it should work and should be looked at by users. A content type should be regarded as an information type, not as a document template. You should use content types to indicate that an item is of a special type, having its own set of metadata. It’s like the example I gave in the article “Using metadata instead of folders”: a car is not the same thing as a house. The document you use is only the container for the content (or the way this content is presented), the content type is the extra information you provide about that content, not about the container of that content.
IMHO, Microsoft should extend the content type mechanism so you can attach more than one template file to it. The example below is a representation of how this could work:
Before Microsoft changes any of that, please make sure you fully understand the concept of content types and that your end users do not confuse the with document templates.
Monday, March 30, 2009
Privacy gap when choosing your own manager
As you’ll know, in a Mysite, a user can edit his profile data. Usually, the Manager field is synchronised with the Active Directory and cannot be filled in by the user:
Setting a manager results in an automatic display of team hierarchy in a treeview consisting of users who share the same manager:
The audience who can see details, can be set on some fields the user can fill in:
My Manager is set by the manager field, My Collegues and My Workgroup are somewhat special. You can add people to your My Collegues group and mark them as member of My Workgroup:
If someone shares the same manager as you, that person will be automatically added to your My Collegues group and markes as My Workgroup as well.
So here’s a catch: if you allow people to set their own manager, they will be automatically added to your My Collegues and My Workgroup!
I’ve tried this on my VM:
- in the SSP, Profile settings, change the manager field to be updatable by users
- create 3 user accounts, give them access to SharePoint and allow them to create a Mysite.
- log in to Windows with user 1 and create a MySite. This user will be the manager.
- now log in to Windows with user 2 and create a MySite. Set user 1 to be the manager. Note: signing in in SharePoint with the user account is not enough as you’ll be redirected to the Mysite of the windows account. Verify the Collegues page.
- now log in to Windows with user 3 and create a MySite. Set user 1 to be the manager.
- Now log in to Windows with user 2 again and go to the Mysite. Check the collegues page to verify that user 3 has now been added to My Collegues and My Workgroup without ever asking for permission.
The impact on security is open to discussion as only some personal details can now be seen by people you didn’t have in mind. Security on list items is not breached as that is set on groups or individual users, not on social distance. However, it’s worth reconsidering whether to allow end users to fill in their own manager.
Monday, February 23, 2009
Using metadata instead of folders
Although a great deal of information is (and opinions are) available on the web, most of them favouring the use of metadata instead of folders, I'd like to add some samples that I use in my daily work. I often use these samples at companies that are "migrating" their file shares to SharePoint (2007 version). Please notice the quotes, intentionally put there to stress that using SharePoint instead of file shares is much more than just a migration: it's a whole new way of work! However, that's a bit out of scope for this article so let's stick to metadata versus folders.
We love to structure our data...
... and that's actually not a bad habit. A common scenario at customers is a file share for project teams that structure their data based on some properties of their projects, like the following example:
- Division a
- Department b
- Project c
- Stage d
- Document 1
- Document 2
- Stage d
- Project c
- Department b
People have worked like this for ages and seem generally satisfied with this solution.
Not so structured after all?
The sample above can work as long as:
- there is good governance on the structure
- there are not too many levels
- you do not have to share document across projects
There might be more properties available than can be used without creating a ridiculously complex folder structure:
- author of the document
- create date of the document
- customer
- version of the document
- project year
- etc.
Often, extra data is stored in the title of the document, like "pid draft version 0.5 - modified by John - to review.doc". From the title, you can get extra information: it's a Project Initiation Document (pid), it's not final, it's been modified by John and should be reviewed. What if it had not been called pid but "prj. in. doc.doc"? It's still a pid, but would you immediately recognise it as such?
Creating duplicates
Using folders for structuring files might work when these files stay within that one folder. However, some files belong to more than one folder. In the folder structure above, 'Document 1' might also belong to 'Project f'. The general solution is creating a copy of the document, causing the following major problems:
- not clear which version is the latest and greatest
- not clear who is the document owner
- need for extra storage
The route to finding information: vertical/horizontal navigation
A folder view is a vertical way of finding information: you'll find the document via a vertical path that someone else has defined. That path might not be the one you want to follow. A great example is a second hand car site. On that site, there are thousands of cars available and you are looking for that one car. Suppose the site had been structured with a folder view, like:
- brand (e.g Mercedes)
- model (e.g 320)
- fuel type (e.g. Petrol)
- colour (e.g. Silver Metallic)
- milage (e.g. 70k-80k)
- colour (e.g. Silver Metallic)
- fuel type (e.g. Petrol)
- model (e.g 320)
That would work if you'd been looking for a Merc. But what if you're looking for a car with the following criteria:
- not more than 5 years old
- petrol
- mileage between 50k-80k
- hatchback
- price between €20k-€35k
The folder view above won't work for you as you'll have to browse each (sub) folder to find cars that match some (but not all ) of your criteria. You don't want a vertical view, you want a horizontal one!
To map this to information within your organisation: you might be able to find the information you're working with because you know the folder structure, but what about all the other employees that might be looking for that information? What about the manager looking for the latest project status reports for all projects?
Did I mention metadata?
We use metadata more often than we think. As Wikipedia describes it: Metadata (meta data, or sometimes metainformation) is "data about other data". In the car example above, the properties of the car are its metadata: information about the car. So if you're looking for a car (age, mileage, etc), a partner (gender, hobbies, etc) or house (type, price, etc), you use metadata to filter. As you can see, each type of object I'm looking for (car, partner, house, etc) will have its own metadata; it wouldn't make much sense to filter on fuel type for a house...
The folder view allows you to add metainformation implicitly, i.e. the location where the item is stored defines its metadata. Once the item is moved to another location, it looses that meta information. Using metadata on the item itself, means that metadata becomes explicit. No matter where you store the item, it keeps its metadata. There are some technical requirements to achieve this, but that will be explained next.
Metadata with SharePoint
Although it's possible to create folders in SharePoint document libraries, I generally do not recommend it: see the sections above. SharePoint implements metadata as columns. End users sometimes find it hard to grasp this concept, but the I use the example of Excel. Almost everyone in an organisation has used Excel so a spreadsheet like the following should look familiar:
Most people also know you can apply filtering in Excel:
And that's also how SharePoint works! (plus more)
SharePoint stores items in lists/libraries and uses columns to provide extra information about the items. SharePoint even allows you to store different types of items (remember the car, partner and house) in one list using so-called content types.
Using metadata, users can now apply filtering, sorting and grouping on the data, either directly or with views.
Retaining metadata when moving items around
I've already mentioned that SharePoint has ways to keep the metadata with the item. Using Content Types is a great way of applying the same metadata structure to lists and libraries. When the item moves to another list that has the same columns, it will keep its metadata. Office files have an even better mechanism build in as metadata is contained within the document itself! Try it out yourself by adding metadata to, for example, a Word document in a library. Now copy the file to another library that does not have the same metadata columns yet. Once you have added the same metadata columns (use the same internal name for the columns!), they will automatically show the metadata. Beyond cool!
Conclusion
Metadata in SharePoint allows you for a much more flexible way of structuring your data than using folders on a file share. When you want to implement SharePoint, leave the folder way of thinking behind and start thinking in more dimensions!
Tuesday, November 18, 2008
Publishing versus collaboration
It has been a while since my last post, so it's time to post once again. This time, it's not something technical. It's related to something me and my collegues at e-office often notice @ customers who are implementing SharePoint.
Solution to what?
What are customers trying to solve by implementing SharePoint? The answers are as divers as hard to get. In many cases, SharePoint is put forward by an IT department as the product to use. If it delivers what the business needs is not clear, but there is confidence that SharePoint can meet any need.
OK, I'm a SharePoint addict and I'm confident you can do a lot with it, OOTB or custom made, but listening to the business is a must do as SharePoint is meant to solve business challenges, not IT challenges (in fact, SharePoint can add a few to those IT challenges...).
Commonly, when you get the answers, SharePoint will be used in an organisation for two types of solutions:
- As a publishing intranet (MOSS), and/or
- As a collaboration environment (WSS)
I know there are many more uses, but for the sake of this post, I'll leave it at these two.
The intranet
MOSS is great for it's OOTB publishing templates: in no time, a complete company intranet can be set up. An intranet has some characteristics:
- it serves as an information channel: its contents are relevant to a broad audience
- it is accessed by many who read, by few who contribute
- its consists mainly of published content (drafts are not visible to the general public)
- the type of content is mainly pages
- its contents is often part of an approval cycle
- its content is often the output of some sort of process, not part of the process itself (like supporting documents)
- its content is highly structured
- style and layout are usually more corporate branded
In short: it's one way traffic on the information highway. There are more characteristics, but the list above is sufficient for the purpose of this post.
The collaboration environment
WSS is great for having team members working together in a virtual environment. This environment has some characteristics:
- it contains content that is only relevant to members of the team
- its content is mainly part of a process, not primarily the final output of this process (example: a team site might be set up for creating a HR reference document which is then published on an intranet)
- the type of content is mainly documents
- there are many contributors, only a few readers
- work in progress (draft) is visible to all members
- its content is free form
- style and layout are functional
There are more characteristics, but the list above is sufficient for the purpose of this post.
Can we do it in the mix?
There's not a problem that we can't fix... (pun intended) but mixing WSS and MOSS can lead to problems that are hard to fix indeed. These are not of the technical kind, but functional. Above, you've seen that MOSS and WSS can be used to achieve great intranets (MOSS) and great collaboration environments (WSS). But when you install MOSS, you have WSS as well and can be tempted to use publishing sites with collaboration elements. Quite often, I meet customers who have implemented MOSS and created an intranet with sites/pages that combine the publishing and collaboration features on a functional level. This results in, for example, department sites that show:
- information about the department ("who are we? What do we do?")
- information for the people within the department (like announcements)
- documents that are part of processes within the department (like draft status handbooks)
The result is a site or page that is only partially interesting for whoever looks at it:
- if you're in that department, you know "who you are" and "what you do"
- if you're not in the department, you are not interested at all in the drafts
Furthermore, because now collaboration and publishing data are mixed, it's virtually impossible to achieve some sort of uniformity or to control what is shown. Also, this can only work when the site map of the intranet reflects the organisational structure. When you have inter-departemental collaboration, you can't reflect that in an intranet where the structure is department oriented. It's quite difficult to publish information on several places (for example: content can be related to a department but also to a theme. Both department and theme have sites/pages in the intranet). Furthermore, what happens if the team moves from one department to another?
Technically, you can work with permissions and audiences to limit what is shown. With metadata and the content by query webpart, you can show information from one area on another. However, this doesn't take away the fact that mixing publishing and collaboration is fundamentally wrong: they are different concepts!
Guidelines and solutions
Here are some guidelines and solutions I usually advise:
- use publishing sites for publishing only
- use team sites for collaboration
- place your collaboration sites either under the sitesdirectory as subsites (easier for central metadata management) or create new site collections (under the managed path "sites"). This makes it much easier to control access. If you expect many sites of a kind, consider using a different web applicayion for collaboration and publishing.
- use metadata and/or workflows/SendTo to show final output created at collaboration site level on the publishing site(s)
- make a visual difference between the collaboration and publishing environment. This makes it easier for the users to see where they are. For a collaboration environment, keep it functional.
- before you start developing, make sure the customer understands the concepts and has defined the business requirements
- provide training for the people who work with it
Never say never
So should you never use publishing features in a collaboration environment? Well, that's not my message. You can use whatever template meets your requirements. If you need to have, for example, news pages within a collaboration environment, why not use a template that enables them. My message is that on the functional level (or better: the content level), you should separate collaboration and publishing. Put some time in the business and functional requirements and then decide how to structure your SharePoint environment and what templates should be used where.
Wednesday, October 22, 2008
passed 70-631
Friday, May 16, 2008
Reghosting feature files
As promised in my blog Error after re-ghosting a page layout, hereby some code to revert files from a specific feature back to their definitions. The code to actually re-ghost the files is taken from Gary Lapointe (http://stsadm.blogspot.com/2007/09/re-ghosting-pages.html). He ran into the same issues I did with files still not being reset and found some workarounds. My addition is a console application that takes a site collection address and a feature ID (GUID) as input parameters to only re-ghost files from that feature. I ran into a scenario where only the files from my feature needed to be re-ghosted, not the other ones.
To do so, I'm looping through the features of the site collection and get the definition of my feature
SPFeatureCollection featureCollection = siteCollection.Features;
foreach (SPFeature feature in featureCollection)
{
if (feature.DefinitionId == featureID)
{
//Get the feature definition
SPFeatureDefinition featureDefinition = feature.Definition;
It's then easy to get the element definitions of this feature:
//Get all element definitions in the feature
SPElementDefinitionCollection elementDefinitionCollection = featureDefinition.GetElementDefinitions(System.Globalization.CultureInfo.InvariantCulture);
foreach (SPElementDefinition elementDefinition in elementDefinitionCollection)
{
//get the XML node of the elements file
XmlNode elementsNode = elementDefinition.XmlDefinition;
XmlNodeList fileNodes = elementsNode.ChildNodes;
This returns an XmlNodeList that you can loop through to find the correct elements. I tried to apply an XPath query to filter on elements GhostableInLibrary, but that failed. Looping through was the only way I could get it to work. DOH!
//perform operation on all files that are ghostable
foreach (XmlNode fileNode in fileNodes)
{
Now I had to check on some attributes:
if (fileNode.NodeType == XmlNodeType.Element && fileNode.Attributes != null)
{
if (fileNode.Attributes["Type"] != null)
{
if (fileNode.Attributes["Type"].Value == "GhostableInLibrary")
{
fileschecked++;
string url = String.Format("{0}/{1}", elementsNode.Attributes["Url"].Value, fileNode.Attributes["Url"].Value);
SPFile file = web.GetFile(url);
if (file.Exists) //Prevents fatal errors when the file has been removed
{
if (file.CustomizedPageStatus == SPCustomizedPageStatus.Customized)
{
This is where the actual re-ghosting method is called.
Here's the complete code. Sorry for the messy layout of code on blogger. I still have to find a way to improve that. Anyway, have fun using and changing it to your needs. Make sure to credit Gary Lapointe as well.
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;
using System.Xml;
using System.Reflection;
namespace RevertToDefinition
{
class Program
{
const string ERR_ARGS = "Please specify a valid url for the site collection and a GUID for the feature.";
const string ERR_GUID = "Invalid feature Guid";
const string ERR_SITECOLLECTION = "Unable to connect to site collection";
static void Main(string[] args)
{
string output = string.Empty;
int fileschecked = 0;
int filesfixed = 0;
int filesnotfixed = 0;
Guid featureID;
SPSite siteCollection;
//check if a parameter has been provided
if (args.Length < 2)
{
Console.WriteLine(ERR_ARGS);
return;
}
//create instance of Program
Program p = new Program();
//Create ref to site collection
try
{
siteCollection = new SPSite(args[0]);
}
catch
{
Console.WriteLine(ERR_SITECOLLECTION);
return;
}
SPWeb web = siteCollection.RootWeb;
//Get Guid
try
{
featureID = new Guid(args[1]);
}
catch
{
Console.WriteLine(ERR_GUID);
return;
}
//get all features activated on this site
SPFeatureCollection featureCollection = siteCollection.Features;
foreach (SPFeature feature in featureCollection)
{
if (feature.DefinitionId == featureID)
{
//Get the feature definition
SPFeatureDefinition featureDefinition = feature.Definition;
//Get all element definitions in the feature
SPElementDefinitionCollection elementDefinitionCollection = featureDefinition.GetElementDefinitions(System.Globalization.CultureInfo.InvariantCulture);
foreach (SPElementDefinition elementDefinition in elementDefinitionCollection)
{
//get the XML node of the elements file
XmlNode elementsNode = elementDefinition.XmlDefinition;
XmlNodeList fileNodes = elementsNode.ChildNodes;
//perform operation on all files that are ghostable
foreach (XmlNode fileNode in fileNodes)
{
if (fileNode.NodeType == XmlNodeType.Element && fileNode.Attributes != null)
{
if (fileNode.Attributes["Type"] != null)
{
if (fileNode.Attributes["Type"].Value == "GhostableInLibrary")
{
fileschecked++;
string url = String.Format("{0}/{1}", elementsNode.Attributes["Url"].Value, fileNode.Attributes["Url"].Value);
SPFile file = web.GetFile(url);
if (file.Exists) //Prevents fatal errors when the file has been removed
{
if (file.CustomizedPageStatus == SPCustomizedPageStatus.Customized)
{
if (p.doRevert(web, file, url))
{
filesfixed++;
}
else
{
filesnotfixed++;
}
}
}
}
}
}
}
}
}
}
//Dispose
web.Dispose();
siteCollection.Dispose();
string notfixed = String.Empty;
if (filesnotfixed > 0)
{
notfixed = String.Format("Unable to fix {0} files.",filesnotfixed.ToString());
}
output = String.Format("{0} files checked, {1} files required fix. {2}", fileschecked.ToString(),filesfixed.ToString(), notfixed);
Console.WriteLine(output);
}
/// <summary>
/// Code below is taken from Gary Lapointe (http://stsadm.blogspot.com/2007/09/re-ghosting-pages.html)
/// His code elaborates on the RevertContentStream as that method might not always do the trick
/// </summary>
/// <param name="file"></param>
private bool doRevert(SPWeb web, SPFile file, string url)
{
bool isFixed = true;
file.RevertContentStream();
file = web.GetFile(url);
if (file.CustomizedPageStatus == SPCustomizedPageStatus.Customized)
{
// Still unsuccessful so take measures further
PropertyInfo requestProp = web.GetType().GetProperty("Request", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.InvokeMethod | BindingFlags.GetProperty);
object request = requestProp.GetValue(web, null);
MethodInfo revertContentStreams = request.GetType().GetMethod("RevertContentStreams", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.InvokeMethod);
// I found some cases where calling this directly was the only way to force the re-ghosting of the file.
// I think the trick is that it's not updating the file properties after doing the revert (the
// RevertContentStream method will call SPRequest.UpdateFileOrFolderProperties() immediately after the
// RevertContentStreams call but ommitting the update call seems to make a difference.
revertContentStreams.Invoke(request, new object[]
{
web.Url, file.Url, file.CheckOutStatus != SPFile.SPCheckOutStatus.None
}
);
MethodInfo dirtyThisFileObject = file.GetType().GetMethod("DirtyThisFileObject", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.InvokeMethod);
dirtyThisFileObject.Invoke(file, new object[] { });
file = web.GetFile(url);
if (file.CustomizedPageStatus == SPCustomizedPageStatus.Customized)
{
Console.WriteLine("Unable to re-ghost file " + file.ServerRelativeUrl);
isFixed = false;
}
else
{
Console.WriteLine(file.ServerRelativeUrl + " was re-ghosted!");
}
}
else
{
Console.WriteLine(file.ServerRelativeUrl + " was re-ghosted!");
}
return isFixed;
}
}
}