Date post: | 31-Dec-2015 |
Category: |
Documents |
Upload: | brook-obrien |
View: | 217 times |
Download: | 0 times |
Deep Dive on Managing Enterprise Content Types At ScaleChris Bortlik, MicrosoftScott Jamison, Jornata
SPC070
SharePoint Technology Specialist
Meet Chris Bortlik
SharePoint Insider
Former Customer
SharePoint 2010 MCITP & MCTS Certifications
Chief Architect &CEO
Microsoft Certified Architect
Meet Scott Jamison
Key Topics
Enterprise Content Type Strategy
Customer Scenario
Working With Site Columns
Managing Content Types
Enterprise Content Type Strategy
Content Types
Sample Content Types
Sales Proposals
Contracts Specifications
Procedures Invoices Training Videos
Sample: Sales ProposalSite ColumnsPotential ClientAmountDue DateSalesperson
TemplateWord Document with consistent branding, formatting, etc.
WorkflowApproval process
PolicyRetention period of 3 years for all proposals
Sales Proposals
Why Content Types?
Consistency.
For both attributes and behavior.
Enterprise Content Type Strategy
Plan Deploy Manage
Planning Identify core metadata values for universal filtering and searching
Identify retention and disposition policies
Identify other foundational elements for content
Determine whether you really need content types at all
Distinguish between enterprise and site-level content type needs
Define policies for the ability to override or self-define content types
Deployment Define site columns, templates, and workflows
Distinguish between enterprise content types, site-level content types, and ad-hoc tags
If needed, define a dedicated site collection for a Content Type Hub for enterprise content types
Assign ownership and governance plan for content types
Management Deploy in TEST environment to ensure behavior is as-intended
Be aware of cross-farm issues with Content Type GUIDs
Train users to understand how/when to use content types
Construct a plan for management over the lifecycle of the content type
Working with Columns
How Columns WorkGUID is the key – not column name
Copy of columns often made
UI pushes all visible properties
OM pushes only edited properties
Before Push Down Ask
What columns are used?
How are they configured?
What columns exist in which sites, lists, or content types?
Are they local or copies of something from a parent site?
Column Usage Report
Managing Content Types
Content Types Associated to site or list
References to columns
Inherited from a parent
Copies can be changed - sometimes
Content Type ReportWhich content types are used on which lists?
How do they relate to the parent content types?
How many list items use a specific content type?
Content Type Report
Creating Content Types
Options
Content Type Syndication
PowerShell 3rd Party Tools
(e.g. AvePoint, Axceler, Metalogix, Quest)
Visual Studio
Site or Site Collection
Site or Site Collection Level
Site or Site Collection LevelProsOut of the box
End user management
Cons
Lack of change management
Scoped to a single site collection
Content Type Hub Introduced in SharePoint 2010
Allows content types to be shared across site collections & farms
Create content types at hub & publish to consumers
Sharing Content Types via Syndication
Publishing content typesContent Types are ‟published” from a
‟normal” Site Content Type GalleryMaximum of 1 Hub per Metadata Shared Application ServiceIt is not a requirement that a
Metadata Service syndicate content
types
It is not a requirement that a service
connection consume content types
from the serviceSetting a site collection to be the hub
enables necessary components on
hub
What gets published?Content Type with all the corresponding columns
Including Document Set Content TypePolicies
And workflow associations (not the
workflows)
Managing Published Content Types
From the hub
Publish
Unpublish
Republish
Roll-up errors from consuming site collections
On the consumer side
Extend a published content type **Derive from a published content type
View import errorsRefresh all content types consumed
from the Hub
** Be careful – read only by default
Content Type Syndication – Publishing from Hub
Farm 1
Web App 1aMetadata Service
Web App 1b
Site Collections 1a/b
Farm 2
Web App 2a
Web App 2b
Connect
ion P
roxy
Site Collections 1cSite Collections 2b
Site Collections 2a
How Content Type Syndication Works
Metadata Service
Connect
ion P
roxy
Subscriber Timer Job
Publish
Each subscriber now has a copy of the original Content Type:• CTs are marked as Read Only• Policies are carried along• Workflow association are established• Updates may be pushed down to list and
libraries
Deleting a Content Type at the Hub
Metadata Service
Connect
ion P
roxy
Subscriber Timer Job
Delete
D
Note: the content Types at the subscriber location are not deleted – they are now Read/Write !
Hub Timer Jo
b
Content Type Syndication Error Logs
Metadata Service
Connect
ion P
roxy
Subscriber Timer Job
! !!
!Hub Timer J
ob
!
!!!!
Content Types Sync has 2 Timer Jobs
• Content Type Hub : deleting and log aggregation• Content Type Subscriber : Cab Pull and Content Type pushdown
Syndication Across EnvironmentsMetadata Service
Connect
ion P
roxy
Subscriber Timer Job
Subs
crib
er T
imer
Job
Publish
Publish
Dev/Test
Production HubProd Auth. Sites
Content Type Publishing
Content Type SyndicationProsOut of the box
End user management
Single source for content types across organization
Cons
Lack of change management
Coordination via dedicated site collection
Does not work for hybrids
ComparisonSite Collection Content Types• Content types used
only by site collection & sub sites
• Can be extended• Changes made on
child sites preserved
Content Type Syndication• Content types can be
used across site collections & farms
• Content types read only by default on consumer sites
• Changes on consumer sites overwritten by publishing hub
PowerShell
PowerShellProsQuick, simple
Repeatable
Change management
ConsRequires IT support
Need to build own management for updates
Visual Studio
Feature Console Application
Visual StudioProsCan deploy with features or as standalone application
Repeatable
Change management
ConsRequires developer support
Need to build own management for updates
3rd Party ToolsProsNo code to support
Most handle hybrid
ConsAdditional licensing cost
Customer Scenario
Global pharmaceutical
3,000 employees worldwide
Regulated content
Customer Scenario
Solution
Customer Scenario
Goals Design Challenges
Goals Desire to have consistent values for content across team sites
Ability for business users to extend items with unique columns
Enforce retention policies
Design Site columns
Content types
Syndicated content types through a content type hub
Retention policies based on content type
Challenges Client needed to both:Push down mandatory columns on all documentsProvide business users the ability to add their own columns
Not possible to do both
Content types were too “heavy” in many scenarios
Many sites, along with many site-level updates, created a situation whereby the use of content types was unknown (how many, how are they used, etc.)
Solution Adjusted usage of enterprise content types (contracts)
Provided better training to end-users
Created PowerShell scripts for column and content type creation as-needed
Created content type reports for better monitoring
Summary
Recap
Develop Your Enterprise Content Type Strategy
Real-World Tips
Work With Site Columns
Manage Content Types
Strategy
Plan
Deploy
Manage
Site ColumnsGUID is the key – not column name
Copy of columns often made
UI pushes all visible properties
OM pushes only edited properties
Content Types
Content Types are either associated to the Site or the List
Contain references to columns but not the column definition
Content Type Hub deploys READ-ONLY copies to subscribing site collections
Real-World TipsRight-size your usage of enterprise content types
Provide training to end-users
Use PowerShell for column and content type creation as-needed
Use content type reports for better monitoring
Wrap-up
Resources The (Hidden) Power of SharePoint Content Types
http://tinyurl.com/spcontenttypes
Creating content typeshttp://tinyurl.com/CreateContentTypehttp://tinyurl.com/ContentTypeConsole
Essential SharePoint 2010http://tinyurl.com/essentialsp2010
Getting started with SharePoint 2013
http://tinyurl.com/sp2013start
Related Sessions
SPC262 What’s new with ECM in SharePoint 2013
SPC020 Best Practices for Records Management with SharePoint
Evaluate this session now on MySPC using your laptop or mobile device: http://myspc.sharepointconference.com
MySPC
Questions?Chris BortlikEmail: [email protected] Blog: blogs.technet.com/cbortlik Twitter: @cbortlik
Scott JamisonEmail: [email protected] Blog: www.scottjamison.com Twitter: @sjam
© 2012 Microsoft Corporation. All rights reserved. Microsoft, Windows, Windows Vista and other product names are or may be registered trademarks and/or trademarks in the U.S. and/or other countries.The information herein is for informational purposes only and represents the current view of Microsoft Corporation as of the date of this presentation. Because Microsoft must respond to changing market conditions, it should not be interpreted to be a commitment on the part of Microsoft, and Microsoft cannot guarantee the accuracy of any information provided after the date of this presentation. MICROSOFT MAKES NO WARRANTIES, EXPRESS, IMPLIED OR STATUTORY, AS TO THE INFORMATION IN THIS PRESENTATION.
Appendix
Column Usage Report
Code: Column Usage Reportclass Program { static void Main(string[] args) { Log("Opening web...");
using (SPSite site = new SPSite("http://intranet.contoso.com/")) { Log("Building report..."); Report = new Report(); report.BuildRowsAndFields(site.RootWeb);
Log("Writing output..."); using (StreamWriter streamWriter = new StreamWriter("ColumnUsageReport.csv")) { report.WriteOutput(streamWriter); } } Log("Done."); }
static void Log(string message) { Console.WriteLine(message); Debug.WriteLine(message); }}
foreach (SPList list in web.Lists .Cast<SPList>() .OrderBy(l => l.ID) .OrderBy(l => l.Title)) { foreach (SPField field in list.Fields) this.GetFieldLabel(field);
ReportRow listRow = new ReportRow(this, list); listRow.Parent = webRow; }
foreach (SPWeb childWeb in web.Webs .OrderBy(w => w.ServerRelativeUrl) .OrderBy(w => w.Title)) { ReportRow childWebRow = this.ScanWeb(childWeb); // recurse
childWebRow.Parent = webRow; } return webRow; } ...}
Code: Column Usage Report
class Report { ...
private ReportRow rootRow = null;
public void BuildRowsAndFields(SPWeb rootWeb) { this.rootRow = ScanWeb(rootWeb); }
private ReportRow ScanWeb(SPWeb web) { ReportRow webRow = new ReportRow(this, web);
foreach (SPField field in web.Fields) this.GetFieldLabel(field);Path URL Associated Content Type Attachments Authenticated Cache Profile Author Auto Update Automatic Update
Team Site / Associated Content Type:1 Attachments:1 Author:1 Auto Update:1 Automatic Update:1Documents /DocumentsEmployees /Lists/Employees Attachments:2Form Templates /FormServerTemplatesImages /PublishingImages Author:2Links /Lists/Links Attachments:2List Template Gallery /_catalogs/ltLong Running Operation Status /Long Running Operation Status Attachments:2Master Page Gallery /_catalogs/masterpage Associated Content Type:2 Authenticated Cache Profile:1Notification List /Notification Pages Attachments:2Pages /PagesProjects /Lists/Projects Attachments:2Quick Deploy Items /Quick Deploy Items Attachments:2Content Management /Content
Announcements /Content/Lists/Announcements Attachments:2Calendar /Content/Lists/Calendar Attachments:2Links /Content/Lists/Links Attachments:2Master Page Gallery:1 /Content/_catalogs/masterpageShared Documents /Content/Shared DocumentsTasks /Content/Lists/Tasks Attachments:2Team Discussion /Content/Lists/Team Discussion Attachments:2Wiki Pages /Content/Wiki Pages
Customer Relationship Management /CRMAnnouncements /CRM/Lists/Announcements Attachments:2Calendar /CRM/Lists/Calendar Attachments:2Links /CRM/Lists/Links Attachments:2Master Page Gallery:1 /CRM/_catalogs/masterpageShared Documents /CRM/Shared DocumentsTasks /CRM/Lists/Tasks Attachments:2Team Discussion /CRM/Lists/Team Discussion Attachments:2Wiki Pages /CRM/Wiki Pages
FAST Search Center /searchDocuments:1 /search/DocumentsImages:1 /search/PublishingImages Author:4Master Page Gallery:1 /search/_catalogs/masterpagePages /search/PagesTabs in Search Pages /search/SearchCenter Attachments:2Tabs in Search Results /search/SearchResults Attachments:2Workflow Tasks /search/WorkflowTasks Attachments:2
Code: Column Usage Reportclass Report { public Dictionary<Guid, ReportField> ReportFieldsById = new Dictionary<Guid, ReportField>(); ...
public string GetFieldLabel(SPField field) { ReportField reportField; if (!this.ReportFieldsById.TryGetValue(field.Id, out reportField)) { reportField = new ReportField(field); this.ReportFieldsById.Add(field.Id, reportField); } return reportField.GetFieldLabelForReport(field); } ...}
class ReportField { private readonly List<string> fieldIdentities = new List<string>();
public readonly string ColumnName; public readonly Guid Id;
public bool EverNotHidden = false;
public ReportField(SPField originalField) { this.ColumnName = originalField.Title; this.Id = originalField.Id; } ...}
Code: Column Usage Reportclass ReportField {
private readonly List<string> fieldIdentities = new List<string>();
...
public string GetFieldLabelForReport(SPField field) { Debug.Assert(field.Id == this.Id); if (!field.Hidden) this.EverNotHidden = true;
int identityNumber = this.GetFieldIdentityNumber(field); string fieldName = field.Title + ":" + identityNumber.ToString();
return field.Hidden ? "(" + fieldName + ")" : fieldName; }
private int GetFieldIdentityNumber(SPField field) {
string fieldIdentity = GetFieldIdentity(field);
if (!fieldIdentities.Contains(fieldIdentity)) fieldIdentities.Add(fieldIdentity);
return fieldIdentities.IndexOf(fieldIdentity) + 1; }
static string GetFieldIdentity(SPField field) { XElement element = XElement.Load( new StringReader(field.SchemaXml));
XElement normalizedElement = GetNormalizedXml(element); normalizedElement.SetAttributeValue("Version", null);
return normalizedElement.ToString().ToLowerInvariant(); }
...}
Code: Column Usage Reportstatic XElement GetNormalizedXml(XElement element) { XElement normalizedElement = new XElement(element.Name);
foreach (XAttribute attribute in element.Attributes() .OrderBy(a => a.Value) .OrderBy(a => a.Name.ToString())) {
if (!string.IsNullOrEmpty(attribute.Value)) normalizedElement.Add(attribute); } foreach (XElement childElement in element.Elements() .OrderBy(e => e.Value) .OrderBy(e => e.Name.ToString())) { normalizedElement.Add( GetNormalizedXml(childElement)); // recurse
if (!string.IsNullOrEmpty(childElement.Value)) normalizedElement.SetValue(childElement.Value.Trim()); }
return normalizedElement;}
<Field ID="{C53A03F3-F930-4ef2-B166-E0F2210C13C0}" Type="Computed" Group="$Resources:core,Document_Columns;" Name="FileType" DisplayName="$Resources:core,File_Type;" ShowInNewForm="FALSE" ShowInFileDlg="FALSE" ShowInEditForm="FALSE" Filterable="TRUE" Sortable="TRUE" AuthoringInfo="$Resources:core,file_extension;" SourceID="http://schemas.microsoft.com/sharepoint/v3/fields" StaticName="FileType"> <FieldRefs> <FieldRef ID="{39360F11-34CF-4356-9945-25C44E68DADE}" Name="File_x0020_Type" /> </FieldRefs> <DisplayPattern> <Column Name="File_x0020_Type" HTMLEncode="TRUE" /> </DisplayPattern></Field>
Code: Column Usage Reportclass ReportRow { public readonly Report Report; private ReportRow parentRow = null;
public readonly string Id;
readonly SPWeb web = null; readonly SPList list = null; public readonly List<ReportRow> ChildRows = new List<ReportRow>();
public string PathName;
public SPList List { get { return this.list; } } public SPWeb Web { get { return this.web; } }
public string Url { get { return this.List != null ? this.List.RootFolder.ServerRelativeUrl : this.Web.ServerRelativeUrl; } }
public SPFieldCollection Fields { get { if (this.List != null) return this.List.Fields; return this.Web.Fields; } }
public ReportRow ParentRow { get { return this.parentRow; } set { if (this.parentRow != null) throw new Exception("ParentRow has already been set"); this.parentRow = value; if (this.parentRow != null) this.parentRow.ChildRows.Add(this); } } ...}
public void WriteOutput(StreamWriter streamWriter, int depth) { Dictionary<string, string> rowValues = new Dictionary<string, string>(1000);
string kind = this.List != null ? "List" : "Web"; rowValues["Kind"] = kind; rowValues["URL"] = this.Url;
string rowIdentity = ""; foreach (SPField field in this.Fields) { string label = this.Report.GetFieldLabel(field); rowValues[field.Id.ToString()] = label; rowIdentity += label; }
int rowIdentityNumber = this.Report.GetRowIdentityNumber( this.PathName, rowIdentity);
rowValues["Path" + depth] = rowIdentityNumber == 0 ? this.PathName : this.PathName + ":" + rowIdentityNumber;
this.Report.WriteRowValues(streamWriter, rowValues, this);
foreach (ReportRow childRow in this.ChildRows) childRow.WriteOutput(streamWriter, depth + 1); }}
Code: Column Usage Report
class ReportRow {
...
public ReportRow(Report ownerReport, SPWeb web) { this.Report = ownerReport; this.web = web; this.Id = web.ID.ToString(); this.PathName = web.Title; }
public int GetMaxDepth() { int maxChildDepth = 0; foreach (ReportRow childRow in this.ChildRows) { maxChildDepth = Math.Max(maxChildDepth, childRow.GetMaxDepth()); } return maxChildDepth + 1; }
...
Path URL Associated Content Type Attachments Authenticated Cache Profile Author Auto Update Automatic UpdateTeam Site / Associated Content Type:1 Attachments:1 Author:1 Auto Update:1 Automatic Update:1
Documents /DocumentsEmployees /Lists/Employees Attachments:2Form Templates /FormServerTemplatesImages /PublishingImages Author:2Links /Lists/Links Attachments:2List Template Gallery /_catalogs/ltLong Running Operation Status /Long Running Operation Status Attachments:2Master Page Gallery /_catalogs/masterpage Associated Content Type:2 Authenticated Cache Profile:1Notification List /Notification Pages Attachments:2Pages /PagesProjects /Lists/Projects Attachments:2Quick Deploy Items /Quick Deploy Items Attachments:2Content Management /Content
Announcements /Content/Lists/Announcements Attachments:2Calendar /Content/Lists/Calendar Attachments:2Links /Content/Lists/Links Attachments:2Master Page Gallery:1 /Content/_catalogs/masterpageShared Documents /Content/Shared DocumentsTasks /Content/Lists/Tasks Attachments:2Team Discussion /Content/Lists/Team Discussion Attachments:2Wiki Pages /Content/Wiki Pages
Customer Relationship Management /CRMAnnouncements /CRM/Lists/Announcements Attachments:2Calendar /CRM/Lists/Calendar Attachments:2Links /CRM/Lists/Links Attachments:2Master Page Gallery:1 /CRM/_catalogs/masterpageShared Documents /CRM/Shared DocumentsTasks /CRM/Lists/Tasks Attachments:2Team Discussion /CRM/Lists/Team Discussion Attachments:2Wiki Pages /CRM/Wiki Pages
FAST Search Center /searchDocuments:1 /search/DocumentsImages:1 /search/PublishingImages Author:4Master Page Gallery:1 /search/_catalogs/masterpagePages /search/PagesTabs in Search Pages /search/SearchCenter Attachments:2Tabs in Search Results /search/SearchResults Attachments:2Workflow Tasks /search/WorkflowTasks Attachments:2
Path URL Associated Content Type Attachments Authenticated Cache Profile Author Auto Update Automatic UpdateTeam Site / Associated Content Type:1 Attachments:1 Author:1 Auto Update:1 Automatic Update:1
Documents /DocumentsEmployees /Lists/Employees Attachments:2Form Templates /FormServerTemplatesImages /PublishingImages Author:2Links /Lists/Links Attachments:2List Template Gallery /_catalogs/ltLong Running Operation Status /Long Running Operation Status Attachments:2Master Page Gallery /_catalogs/masterpage Associated Content Type:2 Authenticated Cache Profile:1Notification List /Notification Pages Attachments:2Pages /PagesProjects /Lists/Projects Attachments:2Quick Deploy Items /Quick Deploy Items Attachments:2Content Management /Content
Announcements /Content/Lists/Announcements Attachments:2Calendar /Content/Lists/Calendar Attachments:2Links /Content/Lists/Links Attachments:2Master Page Gallery:1 /Content/_catalogs/masterpageShared Documents /Content/Shared DocumentsTasks /Content/Lists/Tasks Attachments:2Team Discussion /Content/Lists/Team Discussion Attachments:2Wiki Pages /Content/Wiki Pages
Customer Relationship Management /CRMAnnouncements /CRM/Lists/Announcements Attachments:2Calendar /CRM/Lists/Calendar Attachments:2Links /CRM/Lists/Links Attachments:2Master Page Gallery:1 /CRM/_catalogs/masterpageShared Documents /CRM/Shared DocumentsTasks /CRM/Lists/Tasks Attachments:2Team Discussion /CRM/Lists/Team Discussion Attachments:2Wiki Pages /CRM/Wiki Pages
FAST Search Center /searchDocuments:1 /search/DocumentsImages:1 /search/PublishingImages Author:4Master Page Gallery:1 /search/_catalogs/masterpagePages /search/PagesTabs in Search Pages /search/SearchCenter Attachments:2Tabs in Search Results /search/SearchResults Attachments:2Workflow Tasks /search/WorkflowTasks Attachments:2
Path URL Associated Content Type Attachments Authenticated Cache Profile Author Auto Update Automatic UpdateTeam Site / Associated Content Type:1 Attachments:1 Author:1 Auto Update:1 Automatic Update:1
Documents /DocumentsEmployees /Lists/Employees Attachments:2Form Templates /FormServerTemplatesImages /PublishingImages Author:2Links /Lists/Links Attachments:2List Template Gallery /_catalogs/ltLong Running Operation Status /Long Running Operation Status Attachments:2Master Page Gallery /_catalogs/masterpage Associated Content Type:2 Authenticated Cache Profile:1Notification List /Notification Pages Attachments:2Pages /PagesProjects /Lists/Projects Attachments:2Quick Deploy Items /Quick Deploy Items Attachments:2Content Management /Content
Announcements /Content/Lists/Announcements Attachments:2Calendar /Content/Lists/Calendar Attachments:2Links /Content/Lists/Links Attachments:2Master Page Gallery:1 /Content/_catalogs/masterpageShared Documents /Content/Shared DocumentsTasks /Content/Lists/Tasks Attachments:2Team Discussion /Content/Lists/Team Discussion Attachments:2Wiki Pages /Content/Wiki Pages
Customer Relationship Management /CRMAnnouncements /CRM/Lists/Announcements Attachments:2Calendar /CRM/Lists/Calendar Attachments:2Links /CRM/Lists/Links Attachments:2Master Page Gallery:1 /CRM/_catalogs/masterpageShared Documents /CRM/Shared DocumentsTasks /CRM/Lists/Tasks Attachments:2Team Discussion /CRM/Lists/Team Discussion Attachments:2Wiki Pages /CRM/Wiki Pages
FAST Search Center /searchDocuments:1 /search/DocumentsImages:1 /search/PublishingImages Author:4Master Page Gallery:1 /search/_catalogs/masterpagePages /search/PagesTabs in Search Pages /search/SearchCenter Attachments:2Tabs in Search Results /search/SearchResults Attachments:2Workflow Tasks /search/WorkflowTasks Attachments:2
Content type usage report
Code: Content Type Reportclass Report { Dictionary<string, List<string>> rowIdentitiesByName = new Dictionary<string, List<string>>();
Dictionary<Guid, ReportField> ReportFieldsById = new Dictionary<Guid, ReportField>();
List<KeyValuePair<string, string>> ReportColumnKeysAndTitles = new List<KeyValuePair<string, string>>();
ReportRow rootRow = null; int MaxDepth = 0;
Dictionary<SPContentTypeId, ReportRow> rowsByContentTypeId = new Dictionary<SPContentTypeId, ReportRow>();
...
public void BuildRowsAndFields(SPWeb rootWeb) { this.rootRow = ScanWeb(rootWeb);
this.CollectContentTypes(rootWeb);
ReportRow contentTypeRoot = this.rootRow.ChildRows .First(row => row.IsContentType);
this.PostProcessContentTypes(contentTypeRoot); }
private void CollectContentTypes(SPWeb web) { this.CreateContentTypeRows(web.ContentTypes);
foreach (SPList list in web.Lists) { this.CreateContentTypeRows(list.ContentTypes);
this.MeasureUsage(list); }
foreach (SPWeb childWeb in web.Webs) this.CollectContentTypes(childWeb); // recurse }}
Code: Content Type Reportclass Report { ... private void CreateContentTypeRows( SPContentTypeCollection contentTypes) {
foreach (SPContentType contentType in contentTypes) { ReportRow parentRow = null;
if (!this.rowsByContentTypeId.TryGetValue( contentType.Id.Parent, out parentRow)) {
if (!contentType.Id.Parent.Equals(contentType.Id)) throw new Exception("Cannot find parentRow");
parentRow = this.rootRow; }
ReportRow contentTypeRow = new ReportRow(this, contentType);
contentTypeRow.ParentRow = parentRow;
this.rowsByContentTypeId.Add( contentType.Id, contentTypeRow); } }
private void MeasureUsage(SPList list) { Debug.WriteLine("Querying usage for list: " + list.RootFolder.Url); SPQuery query = new SPQuery(); query.Query = @"<View Scope='RecursiveAll'><ViewFields> <FieldRef Name='FileDirRef'/><FieldRef Name='ContentTypeId'/> </ViewFields></View>";
ContentIterator contentIterator = new ContentIterator(); contentIterator.ProcessListItems(list, delegate(SPListItem listItem) { ReportRow row; if (this.rowsByContentTypeId.TryGetValue( listItem.ContentTypeId, out row)) { ++row.UsageCount; } else { Debug.WriteLine("Error for item " + listItem.Url + ": Content Type Not Found"); } }, delegate(SPListItem listItem, Exception e) { Debug.WriteLine("Error for item " + listItem.Url + ": " + e.Message); return true; } ); }}
Code: Content Type Reportclass Report {
...
private void PostProcessContentTypes(ReportRow contentTypeRow) { List<ReportRow> childRows = contentTypeRow.ChildRows;
// Sort the child rows var sortedRows = childRows .OrderBy(row => row.Url) // if names are the same, sort by URL .OrderBy(row => row.ContentType.Name) .OrderBy(row => row.List == null) // list CT's before web CT's .ToList();
childRows.Clear(); childRows.AddRange(sortedRows);
contentTypeRow.PathName = contentTypeRow.ContentType.Name;
foreach (ReportRow childRow in childRows) this.PostProcessContentTypes(childRow); // recurse }
...
}
Path URL Usages Contributor Copy Source Copyright Country/Region Coverage Created Created Created ByTeam Discussion /Strategy/Lists/Team Discussion (Copy Source:2) Created:2 (Created:2) Created By:2Wiki Pages /Strategy/Wiki Pages Copy Source:3 Created:2 (Created:3) Created By:2
Wiki /wikiDocuments:1 /wiki/Documents Copy Source:3 Created:2 (Created:3) Created By:2Images:3 /wiki/PublishingImages Copy Source:3 Copyright:2 Created:2 (Created:3) Created By:2Master Page Gallery:1 /wiki/_catalogs/masterpage Copy Source:3 Created:2 (Created:3) Created By:2Pages:1 /wiki/Pages Copy Source:3 Created:2 (Created:3) Created By:2Workflow Tasks /wiki/WorkflowTasks (Copy Source:2) Created:2 (Created:2) Created By:2
CONTENT TYPES:System /
Converted Forms /IWConvertedForms Copy Source:3 Created:2 (Created:2) Created By:2List Template Gallery /_catalogs/lt Copy Source:3 Created:2 (Created:3) Created By:2Solution Gallery /_catalogs/solutions Copy Source:3 Created:2 (Created:3) Created By:2Tabs in Search Pages:1 /FastSearch/SearchCenter 4 (Copy Source:2) Created:2 (Created:2) Created By:2Tabs in Search Pages /search/SearchCenter 4 (Copy Source:2) Created:2 (Created:2) Created By:2Tabs in Search Results:1 /FastSearch/SearchResults 5 (Copy Source:2) Created:2 (Created:2) Created By:2Tabs in Search Results /search/SearchResults 3 (Copy Source:2) Created:2 (Created:2) Created By:2Theme Gallery /_catalogs/theme 20 Copy Source:3 Created:2 (Created:3) Created By:2Web Part Gallery /_catalogs/wp Copy Source:3 Created:2 (Created:3) Created By:2Common Indicator Columns /
Excel based Status Indicator /Fixed Value based Status Indicator /SharePoint List based Status Indicator /SQL Server Analysis Services based Status Indicator/
Item /Item:1 /Lists/ContentTypeSyncLogItem:2 /Lists/Customer Contacts 257Item:3 /Lists/Customers 41Item:4 /Lists/DemoProjects 103Item:5 /Lists/Employees 17Item:6 /Lists/Projects 4Item:7 /Lists/Reporting Metadata 11Item:8 /Lists/TaxonomyHiddenList 4Item:9 /Long Running Operation Status 7
Code: Content Type Reportclass ReportField { private readonly List<string> fieldIdentities = new List<string>(); ...
public string GetFieldLabelForReport(SPField field, SPContentType contentType) { Debug.Assert(field.Id == this.Id); if (!field.Hidden) this.EverNotHidden = true;
int identityNumber = this.GetFieldIdentityNumber(field); string fieldName = field.Title + ":" + identityNumber.ToString();
if (contentType != null) { SPFieldCollection sourceFields = contentType.ParentList != null ? contentType.ParentList.Fields : contentType.ParentWeb.Fields; SPField sourceField = sourceFields[field.Id]; int sourceIdentityNumber = this.GetFieldIdentityNumber(sourceField); if (sourceIdentityNumber != identityNumber) fieldName += "/" + sourceIdentityNumber; }
return field.Hidden ? "(" + fieldName + ")" : fieldName; } ...}
Item:13Item:14 Flag Control Display Name:1Announcement
Announcement:1Announcement:1Announcement:1Announcement:1
CirculationCommentContact First Name:1 (First Name Phonetic:2/1)Document
Document:1Document:1Document:1Document:2
Path URL Usages Contributor Copy Source Copyright Country/Region Coverage Created Created Created ByTeam Discussion /Strategy/Lists/Team Discussion (Copy Source:2) Created:2 (Created:2) Created By:2Wiki Pages /Strategy/Wiki Pages Copy Source:3 Created:2 (Created:3) Created By:2
Wiki /wikiDocuments:1 /wiki/Documents Copy Source:3 Created:2 (Created:3) Created By:2Images:3 /wiki/PublishingImages Copy Source:3 Copyright:2 Created:2 (Created:3) Created By:2Master Page Gallery:1 /wiki/_catalogs/masterpage Copy Source:3 Created:2 (Created:3) Created By:2Pages:1 /wiki/Pages Copy Source:3 Created:2 (Created:3) Created By:2Workflow Tasks /wiki/WorkflowTasks (Copy Source:2) Created:2 (Created:2) Created By:2
CONTENT TYPES:System /
Converted Forms /IWConvertedForms Copy Source:3 Created:2 (Created:2) Created By:2List Template Gallery /_catalogs/lt Copy Source:3 Created:2 (Created:3) Created By:2Solution Gallery /_catalogs/solutions Copy Source:3 Created:2 (Created:3) Created By:2Tabs in Search Pages:1 /FastSearch/SearchCenter 4 (Copy Source:2) Created:2 (Created:2) Created By:2Tabs in Search Pages /search/SearchCenter 4 (Copy Source:2) Created:2 (Created:2) Created By:2Tabs in Search Results:1 /FastSearch/SearchResults 5 (Copy Source:2) Created:2 (Created:2) Created By:2Tabs in Search Results /search/SearchResults 3 (Copy Source:2) Created:2 (Created:2) Created By:2Theme Gallery /_catalogs/theme 20 Copy Source:3 Created:2 (Created:3) Created By:2Web Part Gallery /_catalogs/wp Copy Source:3 Created:2 (Created:3) Created By:2Common Indicator Columns /
Excel based Status Indicator /Fixed Value based Status Indicator /SharePoint List based Status Indicator /SQL Server Analysis Services based Status Indicator/
Item /Item:1 /Lists/ContentTypeSyncLogItem:2 /Lists/Customer Contacts 257Item:3 /Lists/Customers 41Item:4 /Lists/DemoProjects 103Item:5 /Lists/Employees 17Item:6 /Lists/Projects 4Item:7 /Lists/Reporting Metadata 11Item:8 /Lists/TaxonomyHiddenList 4Item:9 /Long Running Operation Status 7