This week I've been involved in creating a custom login page for SharePoint 2010 to bypass the standard "select a login method" page for multi-mode claims-enabled web-applications. What we wanted was similar to the Claims Login Web Part for SharePoint Server 2010 for Forms-Based Authentication (FBA) by Jeremy Jameson, but for a trusted ADFS 2.0 identity provider instead.
Having a custom login page allows you to stay in your site, which is more WCAG friendly, and avoid the passive STS authN redirect dance back and forth between SP and the ADFS STS for authentication. This requires you to use active mode (WS-Trust) rather than the passive mode used by SharePoint. Note that this active approach won't give you single sign-on, because you won't get the MSISAuth ADFS SSO cookies - it will simply authenticate you first and then give you the SharePoint FedAuth cookie.
The code you need to call ADFS to make it authenticate you, and thus issue a claims token for use with SharePoint, can be found at Using an Active Endpoint to sign into a Web Application by Dominick Baier or Making a web application use an active STS by Koen Willemse. The missing detail not shown in their code is the URL to the ADFS endpoint, which needs to match the chosen client credentials and security mode; when using UserNameWSTrustBinding and sending the username and password in the WCF message secured using SSL (i.e. mixed), the URL should be like "http://adfs.pzl/adfs/services/trust/13/usernamemixed/" including the important ending / slash to avoid "405 method not allowed" error from IIS.
protected void btnLogin_Click(object sender, EventArgs e)
{
// authenticate with WS-Trust endpoint
var factory = new WSTrustChannelFactory(
new UserNameWSTrustBinding(SecurityMode.TransportWithMessageCredential),
new EndpointAddress ("https://adfs.puzzlepart.com/adfs/services/trust/13/usernamemixed/"));
factory.Credentials.UserName.UserName = txtUserName.Text;
factory.Credentials.UserName.Password = txtPassword.Text;
var channel = factory.CreateChannel();
var rst = new RequestSecurityToken
{
RequestType = RequestTypes.Issue,
AppliesTo = new EndpointAddress("urn:sharepoint:puzzlepart"),
KeyType = KeyTypes.Bearer
};
var genericToken = channel.Issue(rst) as GenericXmlSecurityToken;
// parse token
var handlers = FederatedAuthentication.ServiceConfiguration.SecurityTokenHandlers;
var token = handlers.ReadToken(new XmlTextReader(
new StringReader(genericToken.TokenXml.OuterXml)));
SPSecurity.RunWithElevatedPrivileges(delegate(){
SPFederationAuthenticationModule.Current. SetPrincipalAndWriteSessionToken(token);
});
Response.Redirect("~/pages/default.aspx");
}
After getting authenticated against the ADFS STS when calling Issue on the WS-Trust channel with a RequestSecurityToken, the returned SAML security token must first be parsed and then written to a FedAuth cookie created from the SAML token. The SharePoint FAM wrapper will both set the thread principal and write the cookie, making the user a logged in SharePoint user.
Note how the writing of the cookie is wrapped with RunWithElevatedPrivileges to ensure that it runs as the app-pool identity and not as the impersonated SharePoint user. This is to avoid the dreaded "CryptographicException: The system cannot find the file specified" error in the internal ProtectedDataCookieTransform call.
When calling ValidateToken you will run into the SecurityTokenException: Issuer of the Token is not a Trusted Issuer error if your STS is not trusted by SharePoint. SharePoint is configured to use its own SPPassiveIssuerNameRegistry and that will either validate against the built-in SharePoint STS or the set of trusted STS token issuers. See how to add your STS certificate(s) at SharePoint 2010 Claims-Based Auth with ADFS v2 by Eric Kraus. The trusted providers are apparently only used if the login page is located under the /_trust/ folder that is part of the above "redirect dance" when authenticating against a trusted identity provider.
Over at stack overflow, Matt Whetton had run into the same exception as us and solved it by replacing the passive <issuerNameRegistry> with the Windows Identity Foundation (WIF) ConfigurationBasedIssuerNameRegistry instead. The Configuration of WIF post shows how to add the set of certificate names and thumbprints to the <trustedIssuers> list. This is how your web.config list of trusted STS token issuers may look like:
<issuerNameRegistry type="Microsoft.IdentityModel.Tokens.ConfigurationBasedIssuerNameRegistry, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35">
<trustedIssuers>
<add thumbprint="1337133713371337" name="CN=adfs-puzzlepart" />
<add thumbprint="0000000000000000" name="CN=SharePoint Security Token Service" />
</trustedIssuers>
</issuerNameRegistry>
Remember to add the SharePoint self-issued certificates such as the "SharePoint Security Token Service" certificate to the list of trusted issuers, in addition to your own STS.
I strongly recommend putting your custom ADFS login page under /_trust/ to avoid having to change the SharePoint web.config files. We chose this approach to minimize risks.
Note that Fiddler seems to break the ADFS login process, at least when decrypting SSL.
Disclaimer: Note that even if things seems to work as normal after this configuration change, there is no guarantee that nothing was affected in the huge platform that SharePoint 2010 is. The combination of SP2010 claims and WIF is not very well documented, and any changes beyond supported configuration involves risks. Do not apply these changes if you are not sure that it will not break any of your SharePoint solutions or services.
InfoWorker Solutions
When in doubt, hesitate!
Thursday, January 19, 2012
Tuesday, January 17, 2012
Simple Feature Files Cleanup using Extension Methods
As every seasoned SharePoint developer knows, deactivating a feature does not remove the files deployed by that feature. The deployed masterpages, web part pages, wiki pages, page layouts, web-part definitions, styling artifacts, etc files will stay in the target libraries - and they will not be overwritten on feature activation. Don't let Visual Studio 2010 trick you into believing otherwise.
You have to delete those deployed files yourself in the FeatureDeactivating event. The classic approach is to delete the files one-by-one, but this is tedious and error-prone. The following is a set of extension methods that allows you to simply do this:
public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
{
SPSite site = (SPSite) properties.Feature.Parent;
properties.Definition.DeleteFeatureFiles("MasterPages", site.RootWeb);
properties.Definition.DeleteFeatureWebPartFiles(site.RootWeb);
}
The code is an adaptation of Corey Roth's LINQ to XML and Deleting Files on Feature Deactivation, using extension methods and supporting cleanup of specific feature modules and all feature web-parts.
namespace Puzzlepart.SharePoint.Core.SPExtentions
{
public static class SPFeatureDefinitionExtentions
{
public class Module
{
public string Name { get; set; }
public string Path { get; set; }
public List<string> Files { get; set; }
}
public static void DeleteFeatureFiles(this SPFeatureDefinition spFeatureDefinition, string moduleName, SPWeb web)
{
List<Module> modules = GetModuleFiles(spFeatureDefinition, moduleName);
foreach (Module module in modules)
{
DeleteModuleFiles(module, web);
}
}
public static void DeleteFeatureWebPartFiles(this SPFeatureDefinition spFeatureDefinition, SPWeb web)
{
List<Module> modules = GetAllModuleFiles(spFeatureDefinition);
foreach (Module module in modules)
{
if (string.Compare(module.Path, "_catalogs/wp", StringComparison.CurrentCultureIgnoreCase) == 0)
DeleteModuleFiles(module, web);
}
}
private static List<Module> GetModuleFiles(SPFeatureDefinition spFeatureDefinition, string moduleName)
{
string elementsPath = string.Format(@"{0}\FEATURES\{1}\{2}\Elements.xml", SPUtility.GetGenericSetupPath("Template"), spFeatureDefinition.DisplayName, moduleName);
XDocument elementsXml = XDocument.Load(elementsPath);
XNamespace sharePointNamespace = "http://schemas.microsoft.com/sharepoint/";
// get each module name and the files in it
var moduleList =
from module in elementsXml.Root.Elements(sharePointNamespace + "Module")
select new
{
Name = (module.Attributes("Name").Any()) ? module.Attribute("Name").Value : null,
ModuleUrl = (module.Attributes("Url").Any()) ? module.Attribute("Url").Value : null,
Files = module.Elements(sharePointNamespace + "File")
};
List<Module> modules = new List<Module>();
// iterate through each module with files
foreach (var module in moduleList)
{
Module m = new Module()
{
Name = module.Name,
Path = module.ModuleUrl
};
List<string> files = new List<string>();
foreach (var fileElement in module.Files)
{
string filename = (fileElement.Attributes("Name").Any()) ? fileElement.Attribute("Name").Value : fileElement.Attribute("Url").Value;
files.Add(filename);
}
m.Files = files;
modules.Add(m);
}
return modules;
}
private static void DeleteModuleFiles(Module module, SPWeb web)
{
foreach (string filename in module.Files)
{
if (!string.IsNullOrEmpty(module.Path))
web.GetFile(string.Format("{0}/{1}", module.Path, filename)).Delete();
else
web.Files.Delete(filename);
}
}
private static List<Module> GetAllModuleFiles(SPFeatureDefinition spFeatureDefinition)
{
var moduleList = new List<Module>();
string modulesPath = string.Format(@"{0}\FEATURES\{1}\", SPUtility.GetGenericSetupPath("Template"), spFeatureDefinition.DisplayName);
DirectoryInfo folder = new DirectoryInfo(modulesPath);
foreach (DirectoryInfo moduleFolder in folder.GetDirectories())
{
moduleList.AddRange(GetModuleFiles(spFeatureDefinition, moduleFolder.Name));
}
return moduleList;
}
}
}
Note that page layouts cannot simply be deleted if they are in use. Use code to revert the "GhostableInLibrary" files to the uncustomized (ghosted) feature files on disk in the SharePoint root [14].
You have to delete those deployed files yourself in the FeatureDeactivating event. The classic approach is to delete the files one-by-one, but this is tedious and error-prone. The following is a set of extension methods that allows you to simply do this:
public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
{
SPSite site = (SPSite) properties.Feature.Parent;
properties.Definition.DeleteFeatureFiles("MasterPages", site.RootWeb);
properties.Definition.DeleteFeatureWebPartFiles(site.RootWeb);
}
namespace Puzzlepart.SharePoint.Core.SPExtentions
{
public static class SPFeatureDefinitionExtentions
{
public class Module
{
public string Name { get; set; }
public string Path { get; set; }
public List<string> Files { get; set; }
}
public static void DeleteFeatureFiles(this SPFeatureDefinition spFeatureDefinition, string moduleName, SPWeb web)
{
List<Module> modules = GetModuleFiles(spFeatureDefinition, moduleName);
foreach (Module module in modules)
{
DeleteModuleFiles(module, web);
}
}
public static void DeleteFeatureWebPartFiles(this SPFeatureDefinition spFeatureDefinition, SPWeb web)
{
List<Module> modules = GetAllModuleFiles(spFeatureDefinition);
foreach (Module module in modules)
{
if (string.Compare(module.Path, "_catalogs/wp", StringComparison.CurrentCultureIgnoreCase) == 0)
DeleteModuleFiles(module, web);
}
}
private static List<Module> GetModuleFiles(SPFeatureDefinition spFeatureDefinition, string moduleName)
{
string elementsPath = string.Format(@"{0}\FEATURES\{1}\{2}\Elements.xml", SPUtility.GetGenericSetupPath("Template"), spFeatureDefinition.DisplayName, moduleName);
XDocument elementsXml = XDocument.Load(elementsPath);
XNamespace sharePointNamespace = "http://schemas.microsoft.com/sharepoint/";
// get each module name and the files in it
var moduleList =
from module in elementsXml.Root.Elements(sharePointNamespace + "Module")
select new
{
Name = (module.Attributes("Name").Any()) ? module.Attribute("Name").Value : null,
ModuleUrl = (module.Attributes("Url").Any()) ? module.Attribute("Url").Value : null,
Files = module.Elements(sharePointNamespace + "File")
};
List<Module> modules = new List<Module>();
// iterate through each module with files
foreach (var module in moduleList)
{
Module m = new Module()
{
Name = module.Name,
Path = module.ModuleUrl
};
List<string> files = new List<string>();
foreach (var fileElement in module.Files)
{
string filename = (fileElement.Attributes("Name").Any()) ? fileElement.Attribute("Name").Value : fileElement.Attribute("Url").Value;
files.Add(filename);
}
m.Files = files;
modules.Add(m);
}
return modules;
}
private static void DeleteModuleFiles(Module module, SPWeb web)
{
foreach (string filename in module.Files)
{
if (!string.IsNullOrEmpty(module.Path))
web.GetFile(string.Format("{0}/{1}", module.Path, filename)).Delete();
else
web.Files.Delete(filename);
}
}
private static List<Module> GetAllModuleFiles(SPFeatureDefinition spFeatureDefinition)
{
var moduleList = new List<Module>();
string modulesPath = string.Format(@"{0}\FEATURES\{1}\", SPUtility.GetGenericSetupPath("Template"), spFeatureDefinition.DisplayName);
DirectoryInfo folder = new DirectoryInfo(modulesPath);
foreach (DirectoryInfo moduleFolder in folder.GetDirectories())
{
moduleList.AddRange(GetModuleFiles(spFeatureDefinition, moduleFolder.Name));
}
return moduleList;
}
}
}
Note that page layouts cannot simply be deleted if they are in use. Use code to revert the "GhostableInLibrary" files to the uncustomized (ghosted) feature files on disk in the SharePoint root [14].
Labels:
Programming,
Publishing,
SharePoint,
VisualStudio,
WebPart
Tuesday, January 03, 2012
SharePoint 2010 Localized Publishing Web Template
When you try to create a new localized publishing site based on a minimal SharePoint 2010 publishing web template (or a similar minimal site definition), it might fail with a "CreateWelcomePage" error such as this:
System.Runtime.InteropServices.COMException (0x80070001): 0x80070001 at Microsoft.SharePoint.Library.SPRequestInternalClass.GetMetadataForUrl(String bstrUrl, Int32 METADATAFLAGS, Guid& pgListId, Int32& plItemId, Int32& plType, Object& pvarFileOrFolder) at Microsoft.SharePoint.Library.SPRequest.GetMetadataForUrl(String bstrUrl, Int32 METADATAFLAGS, Guid& pgListId, Int32& plItemId, Int32& plType, Object& pvarFileOrFolder) - -- End of inner exception stack trace --- at Microsoft.SharePoint.SPGlobal.HandleComException(COMException comEx)
at Microsoft.SharePoint.Library.SPRequest.GetMetadataForUrl(String bstrUrl, Int32 METADATAFLAGS, Guid& pgListId, Int32& plItemId, Int32& plType, Object& pvarFileOrFolder) at Microsoft.SharePoint.SPWeb.GetListItem(String strUrl, Boolean bFields, String[] fields) at Microsoft.SharePoint.Publishing.PublishingWeb.GetPublishingPage(String strUrl) at Microsoft.SharePoint.Publishing.Internal.AreaProvisioner.CreateWelcomePage(PublishingWeb area, PageLayout pageLayout) at Microsoft.SharePoint.Publishing.Internal.AreaProvisioner.SetDefaultPageProperties(PublishingWeb area, Boolean& updateRequired) at Microsoft.SharePoint.Publishing.Internal.AreaProvisioner.InitializePublishingWebDefaults() - -- End of inner exception stack trace --- at Microsoft.SharePoint.Publishing.Internal.AreaProvisioner.InitializePublishingWebDefaults() at Microsoft.SharePoint.Publishing.Internal.AreaProvisioner.Provision()
at Microsoft.SharePoint.Publishing.PublishingFeatureHandler.<>c_DisplayClass3.b_0() at Microsoft.Office.Server.Utilities.CultureUtility.RunWithCultureScope(CodeToRunWithCultureScope code) at Microsoft.SharePoint.Publishing.CmsSecurityUtilities.RunWithWebCulture(SPWeb web, CodeToRun webCultureDependentCode) at Microsoft.SharePoint.Publishing.PublishingFeatureHandler.FeatureActivated(SPFeatureReceiverProperties receiverProperties).
The typical cause is that your web template/site definition is a bit too minimal. The "Publishing" feature needs some initial configuration property data during feature activation. Don't strip these properties away completely. Also, activating the "Publishing" feature from code or a feature stapler will not work for localized sites if you don't pass in this configuration. It is not standard, but you can pass property XML data from code to feature activation as shown in Specifying Properties When Activating Features Through Code.
You must pass in the publishing feature property configuration for the "WelcomePageUrl" to ensure that is reference the localized pages library during activation, which is /sider/ for LCID 1044. The fallback for when this property is not set or is empty seems to be hardcoded to /pages/. Note that using "osrvcore" as the resource file is needed for some languages if you don't have SP1 of the language pack installed.
<!-- Feature: Publishing -->
<Feature ID="22A9EF51-737B-4ff2-9346-694633FE4416">
<Properties xmlns="http://schemas.microsoft.com/sharepoint/">
<Property Key="ChromeMasterUrl" Value="~SiteCollection/_catalogs/masterpage/puzzlepart.master" />
<Property Key="WelcomePageUrl" Value="$Resources:cmscore,List_Pages_UrlName;/default.aspx"/>
It is important to reference an existing page in an existing library as the welcome page (home page). Deploy a page using a module if needed. Note that not all of these properties need to be specified as they have working default settings as fallback.
System.Runtime.InteropServices.COMException (0x80070001): 0x80070001 at Microsoft.SharePoint.Library.SPRequestInternalClass.GetMetadataForUrl(String bstrUrl, Int32 METADATAFLAGS, Guid& pgListId, Int32& plItemId, Int32& plType, Object& pvarFileOrFolder) at Microsoft.SharePoint.Library.SPRequest.GetMetadataForUrl(String bstrUrl, Int32 METADATAFLAGS, Guid& pgListId, Int32& plItemId, Int32& plType, Object& pvarFileOrFolder) - -- End of inner exception stack trace --- at Microsoft.SharePoint.SPGlobal.HandleComException(COMException comEx)
at Microsoft.SharePoint.Library.SPRequest.GetMetadataForUrl(String bstrUrl, Int32 METADATAFLAGS, Guid& pgListId, Int32& plItemId, Int32& plType, Object& pvarFileOrFolder) at Microsoft.SharePoint.SPWeb.GetListItem(String strUrl, Boolean bFields, String[] fields) at Microsoft.SharePoint.Publishing.PublishingWeb.GetPublishingPage(String strUrl) at Microsoft.SharePoint.Publishing.Internal.AreaProvisioner.CreateWelcomePage(PublishingWeb area, PageLayout pageLayout) at Microsoft.SharePoint.Publishing.Internal.AreaProvisioner.SetDefaultPageProperties(PublishingWeb area, Boolean& updateRequired) at Microsoft.SharePoint.Publishing.Internal.AreaProvisioner.InitializePublishingWebDefaults() - -- End of inner exception stack trace --- at Microsoft.SharePoint.Publishing.Internal.AreaProvisioner.InitializePublishingWebDefaults() at Microsoft.SharePoint.Publishing.Internal.AreaProvisioner.Provision()
at Microsoft.SharePoint.Publishing.PublishingFeatureHandler.<>c_DisplayClass3.b_0() at Microsoft.Office.Server.Utilities.CultureUtility.RunWithCultureScope(CodeToRunWithCultureScope code) at Microsoft.SharePoint.Publishing.CmsSecurityUtilities.RunWithWebCulture(SPWeb web, CodeToRun webCultureDependentCode) at Microsoft.SharePoint.Publishing.PublishingFeatureHandler.FeatureActivated(SPFeatureReceiverProperties receiverProperties).
The typical cause is that your web template/site definition is a bit too minimal. The "Publishing" feature needs some initial configuration property data during feature activation. Don't strip these properties away completely. Also, activating the "Publishing" feature from code or a feature stapler will not work for localized sites if you don't pass in this configuration. It is not standard, but you can pass property XML data from code to feature activation as shown in Specifying Properties When Activating Features Through Code.
You must pass in the publishing feature property configuration for the "WelcomePageUrl" to ensure that is reference the localized pages library during activation, which is /sider/ for LCID 1044. The fallback for when this property is not set or is empty seems to be hardcoded to /pages/. Note that using "osrvcore" as the resource file is needed for some languages if you don't have SP1 of the language pack installed.
<!-- Feature: Publishing -->
<Feature ID="22A9EF51-737B-4ff2-9346-694633FE4416">
<Properties xmlns="http://schemas.microsoft.com/sharepoint/">
<Property Key="ChromeMasterUrl" Value="~SiteCollection/_catalogs/masterpage/puzzlepart.master" />
<Property Key="WelcomePageUrl" Value="$Resources:cmscore,List_Pages_UrlName;/default.aspx"/>
It is important to reference an existing page in an existing library as the welcome page (home page). Deploy a page using a module if needed. Note that not all of these properties need to be specified as they have working default settings as fallback.
Labels:
Configuration,
Publishing,
SharePoint
Tuesday, November 01, 2011
SharePoint Information Architecture from the Field
Over the years, I've written quite a few articles on how to technically structure your SharePoint solutions into web-apps, sites, subsites, lists and document libraries. All based on having a defined Information Architecture (IA) as a basis for the solution design, or at least being able to reason about your content management using my "chest of drawers" and "news paper" analogies. The latter is based on my experiences from the field as most companies don't have a well-defined IA in place.
Common questions from customers are "what is Information Architecture?" and "what is the value of having an IA for SharePoint, can't we just create sites and doc-libs on the fly as needed?". Not to forget "how do we go about creating an Information Architecture for SharePoint?". So here are some IA advice from Puzzlepart projects:
In short, Information Architecture defines how to classify and structure your content so that it is easy for content consumers to find and explore relevant content, while making it simple for workers to contribute and manage content in an efficient manner.
The business goal of having an Information Architecture for your SharePoint solution is enabling workers to contribute, store and mange content in a manner that is simple and efficient, enabling more content sharing; and at the same time making it easy for workers to browse and find content they need, while also making it easy for workers to discover and explore relevant content they didn't know of. The outcome is more knowledgeable workers that are better informed about what’s going on in the company and about the range of intellectual property possessed by other employees, while also saving time wasted on finding information, and time wasted on incorrect or outdated information.
An outcome is a metric that customers use to define the successful realization of the objectives and goals. Outcomes happens after the project has delivered on its objectives and goals, and the customers must themselves work against securing the outcomes to achieve the desired business value.
The business value of having a working IA is capturing company knowledge from employees with better quality of shared content, which combined with good findability drive more knowledgeable workers that make better decisions and better faster processes. In addition, more and better content sharing helps user not only discover and explore content, but also people such as subject matter experts, allowing employees to build and expand their network throughout the company, helping the company to retain talented employees through social ties and communities. Access to discover more and better content and people expertise is central to enabling innovation and process improvement, as new knowledge is a trigger for new ideas and for identifying new opportunities.
The process of defining your IA for your SharePoint solution should focus on these objectives and goals:
Note that navigation is not IA, its just one way to explore the content. Using navigation to structure your content is just reapplying the fileshare folder approach, which we all know doesn't work too good for findability and discovery. Navigation should not define the statical IA structure for the content, do a LATCH analysis to model the possible IA structures, and choose one of them to define the statical IA structure. The site map is closer to define statical IA structure than navigation, still it is only good for logical IA structure and cannot be expected to be used directly as the physical IA structure in SharePoint.
In an upcoming article I will give some practical advice from the field on how to define and realize the Information Architecture for your SharePoint solution in an agile fashion.
Common questions from customers are "what is Information Architecture?" and "what is the value of having an IA for SharePoint, can't we just create sites and doc-libs on the fly as needed?". Not to forget "how do we go about creating an Information Architecture for SharePoint?". So here are some IA advice from Puzzlepart projects:
In short, Information Architecture defines how to classify and structure your content so that it is easy for content consumers to find and explore relevant content, while making it simple for workers to contribute and manage content in an efficient manner.
The business goal of having an Information Architecture for your SharePoint solution is enabling workers to contribute, store and mange content in a manner that is simple and efficient, enabling more content sharing; and at the same time making it easy for workers to browse and find content they need, while also making it easy for workers to discover and explore relevant content they didn't know of. The outcome is more knowledgeable workers that are better informed about what’s going on in the company and about the range of intellectual property possessed by other employees, while also saving time wasted on finding information, and time wasted on incorrect or outdated information.
An outcome is a metric that customers use to define the successful realization of the objectives and goals. Outcomes happens after the project has delivered on its objectives and goals, and the customers must themselves work against securing the outcomes to achieve the desired business value.
The business value of having a working IA is capturing company knowledge from employees with better quality of shared content, which combined with good findability drive more knowledgeable workers that make better decisions and better faster processes. In addition, more and better content sharing helps user not only discover and explore content, but also people such as subject matter experts, allowing employees to build and expand their network throughout the company, helping the company to retain talented employees through social ties and communities. Access to discover more and better content and people expertise is central to enabling innovation and process improvement, as new knowledge is a trigger for new ideas and for identifying new opportunities.
The process of defining your IA for your SharePoint solution should focus on these objectives and goals:
- Analyze and define the content classification and structure for the solution
- goal: identify what content to manage and plan how to store it in SP, leading to sites, subsites and doc-lib structure organized into SP web-apps
- Analyze and define how to browse and navigate the content
- goal: make it simple and efficient for users to find and use known content that they need in they daily work to drive better faster processes
- Analyze and define how to discover and explore the content
- goal: make it easy for users to stumble upon novel shared knowledge based on "common focus" to trigger innovation and build social ties
- Provide simple and efficient content contributor experience with liberal appliance of default metadata values, storing content close to the authors
- goal: make workers contributors, not knowledge management grunts, and help them store content correctly with better metadata and tagging, driving findability and "common focus" content discovery; drive better sharing and collaboration
- Analyze and define the starter content types with metadata and term set taxonomy based on the defined site and doc-lib architecture, with a strong focus on needed search experience capabilities
- goal: enable content management and support both search-driven and "common focus" content; drive findability, sharing and innovation
- Analyze and define the policies for social tagging and rating in the solution, also in relation to user profile interests, skills and responsibility tagging
- goal: drive "common focus" content discovery, drive findability, drive social communities, drive innovation
- Analyze and define the search experience, focusing on both search-driven content and on search center scopes and refiners
- goal: drive findability and provide both search-driven and "common focus" content
- Enable disposition of redundant and irrelevant content
- goal: provide users with better, correct and up-to-date information, drive findability, save storage cost, save process cost
Note that navigation is not IA, its just one way to explore the content. Using navigation to structure your content is just reapplying the fileshare folder approach, which we all know doesn't work too good for findability and discovery. Navigation should not define the statical IA structure for the content, do a LATCH analysis to model the possible IA structures, and choose one of them to define the statical IA structure. The site map is closer to define statical IA structure than navigation, still it is only good for logical IA structure and cannot be expected to be used directly as the physical IA structure in SharePoint.
In an upcoming article I will give some practical advice from the field on how to define and realize the Information Architecture for your SharePoint solution in an agile fashion.
Labels:
Findability,
IA,
Innovation,
Search,
SearchDriven,
SharePoint,
SiteStructure,
Taxonomy
Subscribe to:
Posts (Atom)
